Skip to content

fix(workflows): if step execute() fails cleanly on a non-list branch#3528

Open
jawwad-ali wants to merge 1 commit into
github:mainfrom
jawwad-ali:fix/control-flow-nonlist-branch-guard
Open

fix(workflows): if step execute() fails cleanly on a non-list branch#3528
jawwad-ali wants to merge 1 commit into
github:mainfrom
jawwad-ali:fix/control-flow-nonlist-branch-guard

Conversation

@jawwad-ali

@jawwad-ali jawwad-ali commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

What

IfThenStep.execute returns config['then']/['else'] directly as StepResult.next_steps with no check that it's a list:

branch = config.get("then", [])
return StepResult(status=COMPLETED, next_steps=branch)   # branch could be "oops" / {...} / 42

The engine does not auto-validate step config before execute(), so an unvalidated run with a non-list branch (a scalar or mapping authoring mistake) passes a non-iterable as next_steps and crashes the whole run. validate() catches this, but execute() should fail the step loudly rather than take down the run.

Fix

Add an isinstance(..., list) guard returning a FAILED StepResult. This completes the same guard #3519 added to the while/do-while steps — whose comment already references the if step as a peer — and mirrors the switch step's cases guard.

Note: this PR originally also touched while/do-while, but #3519 landed that guard for those two steps in the meantime. Rebased down to the still-missing if case only, to avoid duplicating merged work.

Test

Parametrized test_execute_rejects_non_list_branch feeds a str/dict/int branch and asserts FAILED — fails before (the non-iterable next_steps crashed execution), passes after.


🤖 Written with the assistance of Claude Code (AI). Bug self-found; fix/tests verified locally (fail-before / pass-after), ruff clean.

@jawwad-ali jawwad-ali requested a review from mnriem as a code owner July 14, 2026 18:10
IfThenStep.execute returns config['then']/['else'] directly as
StepResult.next_steps with no check that it is a list. The engine does not
auto-validate step config before execute(), so an unvalidated run with a
non-list branch (a scalar or mapping authoring mistake) passes a non-iterable as
next_steps and crashes the whole run. validate() catches this, but execute()
should fail the step loudly instead.

Add an isinstance(list) guard returning a FAILED StepResult, completing the same
guard github#3519 added to the while/do-while steps (and that its comment already
references for the 'if' step) and mirroring the switch step's 'cases' guard.

Parametrized test feeds a str/dict/int branch and asserts FAILED (fails before:
the non-iterable next_steps crashed execution).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jawwad-ali jawwad-ali force-pushed the fix/control-flow-nonlist-branch-guard branch from 9ef71fa to c89db54 Compare July 15, 2026 05:28
@jawwad-ali jawwad-ali changed the title fix(workflows): if/while/do-while execute() fail cleanly on a non-list branch/body fix(workflows): if step execute() fails cleanly on a non-list branch Jul 15, 2026
@jawwad-ali

Copy link
Copy Markdown
Contributor Author

Heads-up: since opening this, #3519 landed the same non-list guard for the while/do-while steps. I've rebased this PR down to the one case #3519 didn't cover — the if step's execute() — so it now complements #3519 rather than duplicating it (and the earlier merge conflict is resolved).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant