Skip to content

fix(workflows): fail switch step on non-mapping cases instead of crashing#3481

Merged
mnriem merged 1 commit into
github:mainfrom
Noor-ul-ain001:fix/switch-nondict-cases-crash
Jul 13, 2026
Merged

fix(workflows): fail switch step on non-mapping cases instead of crashing#3481
mnriem merged 1 commit into
github:mainfrom
Noor-ul-ain001:fix/switch-nondict-cases-crash

Conversation

@Noor-ul-ain001

Copy link
Copy Markdown
Contributor

Summary

SwitchStep.validate() already rejects a non-mapping cases, but the engine's execute() path does not auto-validate — WorkflowEngine.load_workflow's docstring explicitly notes the returned definition is "not yet validated; call validate_workflow() or engine.validate() separately."

On such an unvalidated run, SwitchStep.execute iterated the raw value with cases.items(), so a list or scalar cases (an easy authoring mistake) raised AttributeError. The engine calls step_impl.execute() with no surrounding try/except, so that exception took down the entire run rather than failing just the step.

>>> SwitchStep().execute({"id": "sw", "expression": "x", "cases": ["a", "b"]}, ctx)
AttributeError: 'list' object has no attribute 'items'

Fix

Guard execute to return a FAILED StepResult naming the type error instead of crashing — mirroring the existing fan-out step behavior for a non-list items (test_execute_non_list_items_fails_loudly) and the "report validation errors instead of crashing" direction of #3421. The expression is still evaluated first, so its value is surfaced in the step output for downstream context.

This is the same bug class as the recent max_iterations / timeout / fan-in output guards: a validator catches the bad value, but the runtime path crashes on it when validation is skipped.

Testing

  • Added TestSwitchStep::test_execute_non_dict_cases_fails_loudly (list, str, int cases).
  • Full tests/test_workflows.py passes except the 11 pre-existing Windows symlink-guard tests, which fail identically on a clean base (require elevation on Windows).
  • ruff check clean on the changed files.

🤖 Generated with Claude Code

…hing

`SwitchStep.validate()` already rejects a non-mapping `cases`, but the
engine's `execute()` path does not auto-validate (see
`WorkflowEngine.load_workflow`, whose docstring notes the definition is
"not yet validated"). On an unvalidated run, `execute` called
`cases.items()` on the raw value, so a list or scalar `cases` authoring
mistake raised `AttributeError` and took down the whole run — the engine
invokes `step_impl.execute()` with no surrounding try/except.

Guard `execute` to return a FAILED StepResult naming the type error
instead, mirroring the fan-out step's non-list `items` handling. The
expression is still evaluated first, so its value is surfaced in the
step output for downstream context.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Prevents invalid switch cases values from crashing unvalidated workflow runs.

Changes:

  • Returns a failed StepResult for non-dictionary cases.
  • Adds coverage for list, string, and integer inputs.
Show a summary per file
File Description
src/specify_cli/workflows/steps/switch/__init__.py Adds runtime type guarding.
tests/test_workflows.py Tests graceful failure behavior.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Medium

@mnriem mnriem merged commit e590cd8 into github:main Jul 13, 2026
12 checks passed
@mnriem

mnriem commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Thank you!

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️‍🔥

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • - ]()

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.

4 participants