Skip to content

fix(workflows): reject non-list input 'enum' instead of crashing#3552

Open
Noor-ul-ain001 wants to merge 1 commit into
github:mainfrom
Noor-ul-ain001:fix/input-enum-noniterable-crash
Open

fix(workflows): reject non-list input 'enum' instead of crashing#3552
Noor-ul-ain001 wants to merge 1 commit into
github:mainfrom
Noor-ul-ain001:fix/input-enum-noniterable-crash

Conversation

@Noor-ul-ain001

Copy link
Copy Markdown
Contributor

Problem

A workflow input enum is never type-checked. A scalar value crashes the validator and the runtime input resolver with a raw TypeError instead of producing a clean error:

inputs:
  scope:
    type: string
    enum: 5        # or `true`, `3.14`, ...
TypeError: argument of type 'int' is not a container or iterable

The crash comes from the value not in enum_values membership test in WorkflowEngine._coerce_input. Two paths are affected:

  1. Authoring timevalidate_workflow() documents a "return errors, never raise" contract, but the TypeError escapes its except ValueError and propagates.
  2. Run timeexecute() does not auto-validate the definition (see load_workflow's docstring), so _resolve_inputs hits the same crash when a provided value is coerced.

A bare-string enum (enum: "abc") is silently worse: value in "abc" becomes a substring/character test rather than enum membership, so it passes validation while doing the wrong thing at runtime.

Fix

Require enum to be a list in both places:

  • _coerce_input (the single runtime choke point) raises a clean ValueError on a non-list enum.
  • The authoring-time inputs loop in validate_workflow reports it as a validation error — needed independently because _coerce_input is only reached from validation when a default is present, and the integration: auto case strips enum before coercing.

The redundant "invalid default" report is suppressed when enum is already flagged, so the operator sees one clear error rather than the same problem re-framed twice.

This is the same unvalidated-config crash class as the existing switch / fan-in / fan-out non-list guards.

Tests

Added to tests/test_workflows.py:

  • scalar enum (no default) → clean validation error, no crash
  • string enum → rejected + reported exactly once (no duplicate)
  • scalar enum at run time via _resolve_inputs → clean ValueError, not TypeError
  • valid list enum → still validates and still checks the default against membership

Full test_workflows.py passes except the pre-existing Windows-without-elevation symlink-guard tests (unrelated to this change).

🤖 Generated with Claude Code

A workflow input `enum` was never type-checked, so a scalar value
(`enum: 5`, `enum: true`) made the `value not in enum_values`
membership test raise a raw `TypeError` ("argument of type 'int' is not
... iterable"). This escaped `validate_workflow`'s `except ValueError`,
breaking its documented "return errors, never raise" contract, and
crashed `_resolve_inputs` outright at run time (`execute` does not
auto-validate the definition first). A bare-string `enum` was silently
worse: `value in "abc"` is a substring/character test, not enum
membership.

Require `enum` to be a list in both `_coerce_input` (the single runtime
choke point) and the authoring-time inputs loop (so a bad `enum` on an
input with no `default`, or the `integration: auto` case that strips
`enum` before coercion, is still caught). Suppress the redundant
"invalid default" report when `enum` is already flagged, so the operator
sees one clear error.

Same unvalidated-config crash class as the switch/fan-in/fan-out
non-list guards.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Noor-ul-ain001 Noor-ul-ain001 requested a review from mnriem as a code owner July 15, 2026 17:31
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