Workflow tool: args object delivered to script as JSON string (schema's untyped `args` → model emits string; dup of #72248) — bug 2 in original report retracted
Environment
- Claude Code version: 2.1.201 (native install, macOS / Darwin 25.5.0)
- Session model:
claude-fable-5 - Both bugs observed in a single Workflow run (52 subagents, dynamic script via the
Workflowtool), reproduced consistently within that session.
Two related bugs in the Workflow/background-task subsystem, found in one run. Happy to split into separate issues if preferred.
---
Bug 1: Workflow args object is delivered to the script as a JSON string
The Workflow tool docs state:
args: any— the value passed as Workflow'sargsinput, verbatim. Pass arrays/objects as actual JSON values in the tool call, NOT as a JSON-encoded string.
The model passed args as a proper JSON object in the tool call:
{ "script": "...", "args": { "skills": [ {"name": "...", "path": "..."}, ... ] } }
But inside the script, args arrived as a JSON-encoded string, so args.skills was undefined and the run crashed immediately:
TypeError: pipeline() expects an array as the first argument
at <anonymous> (/$bunfs/root/src/entrypoints/cli.js:6602:4054)
The failure notification's recovery snippet also shows the harness itself re-encoding args as a string:
Workflow({scriptPath: '...', resumeFromRunId: '...', args: "{\"skills\": [{\"name\": ...
Workaround (confirmed working): defensive parse at the top of the script:
const input = typeof args === 'string' ? JSON.parse(args) : args
Expected: args reaches the script as the same JSON value passed in the tool call.
---
Bug 2: Premature completed task-notification while the workflow is still running; output file empty at that point
Timeline of a 52-agent workflow run (task id w1tfx6dkg):
- T+9min — a
<task-notification>fired withstatus: completed, claimingagents_done: 52andduration_ms: 541317, including aResult:preview and pointing to the task output file. - At that moment the output file was 0 bytes (
wc -c→ 0), the workflow journal (journal.jsonl) contained only ~10 of 52 agent results, andTaskOutput(block:false)returnedstatus: running— i.e. the notification was false. - The journal kept growing for another ~15 minutes.
- T+24min — a second, correct notification fired (
duration_ms: 1447553,agents_done: 52), and the output file was then written correctly (325 KB, valid{summary, agentCount, logs, result}JSON).
Inconsistencies in the premature notification:
status: completedwhile the run was still executing (contradicted byTaskOutputand by the still-growing journal)agents_done: 52when only ~10 results existed in the journalsubagent_tokens: 1082815vs the final4640892(so the "done" count could not have been real)- output-file path provided, but the file was empty
Impact: a model (or user tooling) that trusts the first notification reads an empty/partial result and may conclude the workflow produced nothing. The TaskOutput re-check is a viable workaround, but the notification contract ("you will be notified when it completes") is broken by the early false-positive event.
Expected: exactly one completed notification, emitted after the run actually finishes and the output file is flushed.
---
Notes
- Both bugs were worked around in-session (defensive
JSON.parse; re-verifying completion viaTaskOutput+ journal growth), so this is a report, not a blocker. - The per-agent results in
journal.jsonlwere complete and correct in both runs — only the args passing and the notification/output-file timing misbehaved.
🤖 Filed via Claude Code on behalf of the account owner.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗