fix(workflows): fail a fan-in step whose output is not a mapping - #3887
Open
jawwad-ali wants to merge 1 commit into
Open
fix(workflows): fail a fan-in step whose output is not a mapping#3887jawwad-ali wants to merge 1 commit into
output is not a mapping#3887jawwad-ali wants to merge 1 commit into
Conversation
execute() did:
output_config = config.get("output") or {}
if not isinstance(output_config, dict):
output_config = {}
so every non-mapping `output` was silently discarded and the step still
returned COMPLETED — every declared aggregation key vanished, and
downstream `{{ steps.<id>.output.<key> }}` resolved to None and
interpolated as an empty string:
output=[] -> completed, error=None
output=False -> completed, error=None
output=0 -> completed, error=None
output='' -> completed, error=None
output=['a'] -> completed, error=None
output='oops' -> completed, error=None
output=5 -> completed, error=None
`validate` already rejects this and its comment names the flaw exactly:
"execute() silently coerces a non-mapping output to {}, so the author's
declared aggregation keys would vanish with no error." The engine does not
auto-validate before execute(), so on an unvalidated run that is what
happened — and `x or {}` masked the falsy shapes before the isinstance
check even ran.
Fail loudly with validate()'s own message, mirroring the `wait_for` guard
in the same method. An explicit `output:` (YAML null) stays valid.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Problem
FanInStep.executebegan with:Any non-mapping
outputwas silently replaced with{}and the step still returned COMPLETED. Every aggregation key the author declared vanished, and downstream{{ steps.<id>.output.<key> }}resolved toNoneand interpolated as an empty string.Note also that
x or {}masked the falsy shapes ([],false,0,'') before theisinstancecheck even ran.Reproduction on current
main(81bf741)This is already a known flaw — in this file
validaterejects a non-mappingoutput, and its comment names the execute-side bug outright:The engine does not auto-validate before
execute(seeWorkflowEngine.load_workflow), so on an unvalidated run that comment describes exactly what happens. This PR closes the execute-side half.Fix
Fail the step with validate()'s own message, mirroring the
wait_forguard a few lines below in the same method:This is the same "silent empty result + COMPLETED" class the
wait_forguards in this method already reject, and the same shape as the fan-out non-listitemsguard.No breaking change. An explicit
output:(YAML null) stays valid, matchingvalidate— pinned by a second new test. A mapping behaves exactly as before. The only inputs whose behaviour changes are ones that silently produced an empty aggregation.Verification
srcand pass with the fix.tests/test_workflows.pyscoped regression: failure set identical to the clean-mainbaseline captured on81bf741(20 pre-existing in this file, all Windows symlink-privilege).uvx ruff@0.15.0 check src tests→ cleanTests go into the existing
TestFanInStep, besidetest_execute_non_list_wait_for_fails_loudly— the sibling guard whose docstring describes the same wiring bug.Written with assistance from Claude Code. Bug found, reproduced, and verified by me on current
main.