Skip to content

fix(workflows): fail fan-out loudly on a truthy non-mapping step template#3537

Open
Noor-ul-ain001 wants to merge 1 commit into
github:mainfrom
Noor-ul-ain001:fix/fanout-nondict-template-crash
Open

fix(workflows): fail fan-out loudly on a truthy non-mapping step template#3537
Noor-ul-ain001 wants to merge 1 commit into
github:mainfrom
Noor-ul-ain001:fix/fanout-nondict-template-crash

Conversation

@Noor-ul-ain001

Copy link
Copy Markdown
Contributor

@

Summary

A fan-out step whose step: field is a truthy scalar or list (an authoring mistake) passed execute(), produced a COMPLETED result, and reached the engine — which calls template.get("id", ...) in _run_fan_out (engine.py, guarded only by if template and items:). A non-dict step raised AttributeError there, with no surrounding try/except, taking down the whole run instead of failing the single step.

validate() already rejects a non-mapping step, but the engine does not auto-validate (see WorkflowEngine.load_workflow), so an unvalidated run crashed. This is the same bug class as the switch non-dict cases and fan-in non-list wait_for guards.

Changes

  • fan_out/__init__.py: guard execute() to FAIL the step with a clear error and normalized empty output when step is not a mapping — mirroring the existing non-list items guard and the switch cases guard.
  • tests/test_workflows.py: add test_execute_non_dict_step_fails_loudly covering list/scalar/int step values. (validate was already covered by test_validate_step_not_mapping; the execute()-path guard was not.)

Testing

All 25 fan-out tests pass locally.

🤖 Generated with Claude Code
@

…late

A fan-out step whose `step:` is a truthy scalar or list (an authoring mistake) passed execute and reached the engine, which calls template.get("id", ...) in _run_fan_out — raising AttributeError and taking down the whole run. validate already rejects a non-mapping step, but the engine does not auto-validate, so an unvalidated run crashed.

Guard execute to FAIL the step (with a clear error and normalized empty output) instead, mirroring the existing non-list items guard and the switch non-dict cases guard. Add the matching test_execute_non_dict_step_fails_loudly covering the execute-path guard (validate was already covered).

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 malformed fan-out step templates from crashing workflow runs.

Changes:

  • Rejects non-dictionary fan-out templates during execution.
  • Adds regression coverage for list and scalar templates.
Show a summary per file
File Description
src/specify_cli/workflows/steps/fan_out/__init__.py Adds the runtime type guard.
tests/test_workflows.py Tests malformed template handling.

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: 1
  • Review effort level: Medium

# unvalidated run instead, mirroring the ``items`` guard below. An empty
# or absent ``step`` defaults to ``{}`` (falsy) and the engine's
# ``if template and items`` skips fan-out, so it stays valid here.
if not isinstance(step_template, dict):

@mnriem mnriem left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please address Copilot feedback

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.

3 participants