Workflow tool: args not delivered to a workflow that validates inputs at the top (regression ~2.1.158→2.1.185)

Open 💬 1 comment Opened Jun 27, 2026 by amiros-stanf

What happened

A workflow script (.claude/workflows/*.js) launched via the Workflow tool no longer receives its passed args when the first executable statement is a conditional guard (validation). Instead the guard fires as if args were a placeholder object missing my fields, and that guard's early return/throw is surfaced as the run result (agentCount: 0, ~12 ms, no agents run).

This worked correctly ~2 days ago and now reproduces 100% — a regression.

Minimal reproduction

Workflow A (fails):

export const meta = { name: 'argbug-a', description: 'guard first', phases: [{ title: 'P' }] }
phase('P')                                   // tried with and without a leading phase()
if (!args || !args.company) return { error: 'company required' }
return { got: args }

Launch: Workflow({ scriptPath: ".../argbug-a.js", args: { company: "X", y: 1 } })
Result: { "error": "company required" } ← args.company was absent in the surfaced pass.

Workflow B (works) — identical except the first statement is an unconditional return:

export const meta = { name: 'argbug-b', description: 'return first', phases: [{ title: 'P' }] }
return { got: args }

Launch: Workflow({ scriptPath: ".../argbug-b.js", args: { company: "X", y: 1 } })
Result: { "got": { "company": "X", "y": 1 } } ← correct args delivered.

So the same launch (scriptPath + args) delivers args to an unconditional first-statement return but not to a conditional guard. Workflow({ name, args }) behaves the same as scriptPath. Identical content with an unconditional early return { got: args } inserted before the guard also receives the real args.

Hypothesis

The runtime appears to execute the body in two passes — a metadata/structure-extraction pre-pass with placeholder/empty args (agents stubbed), then the real pass with the caller's args. A top-level conditional early return/throw during the pre-pass aborts it and its result is surfaced instead of the real pass. Per the docs guidance I moved validation to after the first phase() call — this did not fix it.

Impact

Any workflow that validates its inputs at the top (the natural, recommended pattern) is unrunnable: it returns its own validation error before the real run. This blocks a multi-workflow pipeline I converted recently. The exact same workflow ran end-to-end successfully ~2 days earlier on an older CLI build (it produced full multi-agent output), so this is a regression.

Environment

  • Claude Code 2.1.185 (Windows 11). A second machine on 2.1.158. Changelog latest is 2.1.195.
  • Workflow runtime stack frames reference a bundled Bun runtime (B:/~BUN/root/src/entrypoints/cli.js).

Ask

  1. Is the two-pass (metadata pre-pass + real pass) model intended, and what args does the pre-pass receive?
  2. What is the supported input-validation idiom that survives the pre-pass and still aborts cleanly on genuinely missing args in the real run?
  3. Was arg delivery to guarded workflows changed between ~2.1.158 and 2.1.185?

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗