Repository navigation
Python: fix(declarative): treat omitted workflow inputs as blank in PowerFx - #9730
Draft
Naveen Chatlapalli (1aifanatic) wants to merge 1 commit into
Conversation
…owerFx
When a caller omits an input that a formula references, PowerFx fails to
compile inputs.<name> / Workflow.Inputs.<name> ("Name isn't valid") and
eval() returns None for the whole expression. That breaks the documented
default pattern =If(IsBlank(inputs.name), "World", inputs.name): the
simple_workflow sample printed "Hello, !" for workflow.run({}).
Bind referenced-but-missing inputs to blank for that evaluation only, the
same result as passing the input as None, without writing them to state.
Also print the simple_workflow sample's second run, which was discarded.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Naveen Chatlapalli (1aifanatic)
temporarily deployed
to
github-app-auth
October 26, 2026 18:36 — with
GitHub Actions
Inactive
Naveen Chatlapalli (1aifanatic)
temporarily deployed
to
github-app-auth
October 26, 2026 18:36 — with
GitHub Actions
Inactive
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Reference discovery matches literal and comment text while missing valid quoted and whitespace-separated references.
2 open issues
What changed in this PR
This PR addresses #9729 by binding omitted workflow inputs as blank during PowerFx evaluation, allowing default expressions to run without modifying workflow state.
Changes:
- Adds evaluation-only blank bindings for references through both input aliases.
- Tests omitted-input defaults and verifies state remains unchanged.
- Prints the custom-name run’s outputs in the simple workflow sample.
| File | Description |
|---|---|
python/samples/03-workflows/declarative/simple_workflow/main.py |
Prints outputs from the “Alice” run. |
python/packages/declarative/tests/test_powerfx_yaml_compatibility.py |
Adds missing-input regression tests for both aliases. |
python/packages/declarative/agent_framework_declarative/_workflows/_declarative_base.py |
Discovers missing input references and binds evaluation-only blanks. |
Review effort: Balanced
|
|
||
|
|
||
| _ENV_REFERENCE_RE = re.compile(r"\bEnv\.([A-Za-z_][A-Za-z0-9_]*)") | ||
| _INPUT_REFERENCE_RE = re.compile(r"(?<![\w.])(?:inputs|Workflow\.Inputs)\.([A-Za-z_][A-Za-z0-9_]*)") |
| if not isinstance(inputs, Mapping): | ||
| return symbols | ||
| input_values = cast(Mapping[str, Any], inputs) | ||
| missing = {name for name in _INPUT_REFERENCE_RE.findall(formula) if name not in input_values} |
This branch was previously deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Motivation & Context
=If(IsBlank(inputs.name), "World", inputs.name)never applies its default when the caller omitsname, so thesimple_workflowsample printsHello, !forworkflow.run({}). PowerFx fails to compileinputs.namewhen the inputs record has no such field, andDeclarativeWorkflowState.eval()returnsNonefor the whole expression. Details and an input matrix are in #9729.Description & Review Guide
_bind_missing_input_references()findsinputs.<name>/Workflow.Inputs.<name>references in the formula. Any input the caller did not supply is bound to blank (None) in that evaluation's PowerFx symbols, for both aliases. Workflow state is not modified, and other undefined names keep the existingNonebehavior. The regex follows the existing_ENV_REFERENCE_REapproach forEnv.<name>.test_if_with_isblank_when_input_is_missing, next totest_if_with_isblank, which only covered{"name": ""}. It checks both aliases and that the missing key is not written to state.simple_workflowsample now prints the outputs of its second ("Alice") run, which were discarded.None. Expressions that previously evaluated toNoneonly because an input was absent now evaluate normally with that input blank.inputs:schema, butsimple_workflowdoes not declare its inputs.Verification, with the .NET 10 runtime for PowerFx:
mainassert None == 'World'simple_workflowsampleHello, !, then no output for AliceHello, World!,Hello, Alice!packages/declarative/testsPyright on
_declarative_base.pyreports 0 errors. Mypy reports the same 5 errors before and after (none on the changed lines).ruff checkandruff format --checkpass.Related Issue
Fixes #9729
AI Assistance
AI assistance details: Claude Code helped find the bug by running the declarative samples locally, trace it to
DeclarativeWorkflowState.eval(), implement the fix and test, and draft this description and the linked issue.Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.🤖 Generated with Claude Code