[BUG] workflow subagents receive a substituted tool input, making every parameterized tool call fail schema validation

Status Open
Reported on v2.1.220
Maintainer reply None cached
Activity 1 comment · opened Jul 31, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Bug: workflow subagents receive a substituted tool input, making every parameterized tool call fail schema validation

Environment

  • Claude Code 2.1.220
  • Node v22.22.2, Linux
  • Claude Code on the web (remote execution environment / SDK harness)
  • Occurs in subagents spawned by the Workflow tool. The main session is unaffected.

Summary

Inside workflow subagents, tool calls intermittently fail because the input the model emitted is replaced with a different object before schema validation. The model's input is well-formed — the error message itself confirms this ("The tool input from the model was valid"). The affected agent can then perform no work at all: every Read, Bash, Grep, Glob, and ToolSearch call fails, and the agent eventually dies on the StructuredOutput retry cap.

In one run this produced 202 occurrences across 12 subagents, which burned ~484k tokens and ~10.6 minutes of wall clock to accomplish nothing.

Symptom A — parameterized tools lose their required parameters

<tool_use_error>The permission handler returned updatedInput for Bash that failed schema validation:
Bash failed due to the following issue:
The required parameter `command` is missing
This is a configuration issue in your canUseTool callback, PermissionRequest hook, or
permission-prompt tool — updatedInput must satisfy the tool's input schema.
The tool input from the model was valid.</tool_use_error>

Identical errors for Read (file_path missing), Grep / Glob (pattern missing), ToolSearch (query missing).

Breakdown from a single affected run:

| Tool | Occurrences |
|---|---|
| Read | 66 |
| Bash | 63 |
| Grep | 16 |
| Glob | 15 |
| (empty tool name) | 15 |
| ToolSearch | 9 |
| Total | 202 |

Note the 15 occurrences where the tool name renders as empty — possibly a related symptom.

Symptom B — StructuredOutput fails the same way, and this one pinpoints the cause

The workflow used agent(prompt, { schema }). The subagent emitted a fully schema-conformant call:

// keys actually present in the model's tool_use input:
["correctedSeverity", "deliberateDeferral", "evidence", "isReal", "rationale", "stillApplies", "suggestedFix"]

The schema's five required properties were isReal, stillApplies, correctedSeverity, rationale, evidenceall present. Yet validation returned:

Output does not match required schema:
  root: must have required property 'isReal',
  root: must have required property 'stillApplies',
  root: must have required property 'correctedSeverity',
  root: must have required property 'rationale',
  root: must have required property 'evidence',
  root: must NOT have additional properties,
  root: must NOT have additional properties,
  root: must NOT have additional properties

So the validator saw none of the 7 keys the model sent, and instead saw exactly 3 keys that are not in the schema.

Likely root cause

The two symptoms are consistent with one defect: the permission layer's own response envelope is being passed to the tool/validator in place of the model's input.

  • A ~3-key envelope (something shaped like { behavior, updatedInput, ... }) explains Symptom B exactly: zero schema properties present, three additional properties rejected.
  • The same substitution explains Symptom A: an envelope has no command / file_path / pattern, so each tool reports its required parameter missing.

That is, updatedInput appears to be set to the wrapper object rather than to the inner input payload.

Frequency and what it does not correlate with

Intermittent — roughly one run in three completed healthily. It is not model-linked:

| Run | Subagent model | Permission errors | Outcome |
|---|---|---|---|
| A | claude-fable-5 | 0 | 16/16 agents succeeded |
| B | claude-fable-5 | 60 | all 5 agents failed |
| C | claude-opus-5 | 202 | all 12 agents failed |

The same model appears on both a clean run and a failing run, so switching models is not a workaround.

There is no PermissionRequest hook and no settings.json / settings.local.json in either the project or the user config directory, so this is not user hook configuration — it points at the canUseTool callback in the SDK harness that spawns workflow subagents.

Impact

  1. The subagent cannot read a single byte, so it produces no analysis.
  2. It exhausts the StructuredOutput retry cap (5) and dies with TelemetrySafeError: StructuredOutput retry cap (5) exceeded.
  3. The parent workflow reports every agent as failed after substantial token spend.

Secondary risk worth flagging: a workflow that post-processes verdicts can silently mislabel these failures. In our case an earlier script bucketed findings with !result.verdict?.isReal, so agents that died this way were reported as "refuted" — i.e. actively dismissed as non-issues — rather than "unverified". Notably, the subagents themselves handled this correctly: they attempted to return rationale: "UNVERIFIED due to tool failure; not a refutation", but that call was itself blocked by this bug, so the honest signal never escaped.

Suggested fix

In the subagent permission path, ensure updatedInput is assigned the inner tool-input payload rather than the permission-decision wrapper — and consider failing loudly if updatedInput does not validate against the tool schema, instead of forwarding it to the tool.

Reproduction notes

Not reliably reproducible on demand due to the intermittency. Occurs with Workflow running ~12 concurrent subagents, each using agent(prompt, { schema }) with a JSON Schema containing required and additionalProperties: false.

What Should Happen?

subagents should run full verification and report back without error

Error Messages/Logs

Steps to Reproduce

Bug: workflow subagents receive a substituted tool input, making every parameterized tool call fail schema validation

Environment

  • Claude Code 2.1.220
  • Node v22.22.2, Linux
  • Claude Code on the web (remote execution environment / SDK harness)
  • Occurs in subagents spawned by the Workflow tool. The main session is unaffected.

Summary

Inside workflow subagents, tool calls intermittently fail because the input the model emitted is replaced with a different object before schema validation. The model's input is well-formed — the error message itself confirms this ("The tool input from the model was valid"). The affected agent can then perform no work at all: every Read, Bash, Grep, Glob, and ToolSearch call fails, and the agent eventually dies on the StructuredOutput retry cap.

In one run this produced 202 occurrences across 12 subagents, which burned ~484k tokens and ~10.6 minutes of wall clock to accomplish nothing.

Symptom A — parameterized tools lose their required parameters

<tool_use_error>The permission handler returned updatedInput for Bash that failed schema validation:
Bash failed due to the following issue:
The required parameter `command` is missing
This is a configuration issue in your canUseTool callback, PermissionRequest hook, or
permission-prompt tool — updatedInput must satisfy the tool's input schema.
The tool input from the model was valid.</tool_use_error>

Identical errors for Read (file_path missing), Grep / Glob (pattern missing), ToolSearch (query missing).

Breakdown from a single affected run:

| Tool | Occurrences |
|---|---|
| Read | 66 |
| Bash | 63 |
| Grep | 16 |
| Glob | 15 |
| (empty tool name) | 15 |
| ToolSearch | 9 |
| Total | 202 |

Note the 15 occurrences where the tool name renders as empty — possibly a related symptom.

Symptom B — StructuredOutput fails the same way, and this one pinpoints the cause

The workflow used agent(prompt, { schema }). The subagent emitted a fully schema-conformant call:

// keys actually present in the model's tool_use input:
["correctedSeverity", "deliberateDeferral", "evidence", "isReal", "rationale", "stillApplies", "suggestedFix"]

The schema's five required properties were isReal, stillApplies, correctedSeverity, rationale, evidenceall present. Yet validation returned:

Output does not match required schema:
  root: must have required property 'isReal',
  root: must have required property 'stillApplies',
  root: must have required property 'correctedSeverity',
  root: must have required property 'rationale',
  root: must have required property 'evidence',
  root: must NOT have additional properties,
  root: must NOT have additional properties,
  root: must NOT have additional properties

So the validator saw none of the 7 keys the model sent, and instead saw exactly 3 keys that are not in the schema.

Likely root cause

The two symptoms are consistent with one defect: the permission layer's own response envelope is being passed to the tool/validator in place of the model's input.

  • A ~3-key envelope (something shaped like { behavior, updatedInput, ... }) explains Symptom B exactly: zero schema properties present, three additional properties rejected.
  • The same substitution explains Symptom A: an envelope has no command / file_path / pattern, so each tool reports its required parameter missing.

That is, updatedInput appears to be set to the wrapper object rather than to the inner input payload.

Frequency and what it does not correlate with

Intermittent — roughly one run in three completed healthily. It is not model-linked:

| Run | Subagent model | Permission errors | Outcome |
|---|---|---|---|
| A | claude-fable-5 | 0 | 16/16 agents succeeded |
| B | claude-fable-5 | 60 | all 5 agents failed |
| C | claude-opus-5 | 202 | all 12 agents failed |

The same model appears on both a clean run and a failing run, so switching models is not a workaround.

There is no PermissionRequest hook and no settings.json / settings.local.json in either the project or the user config directory, so this is not user hook configuration — it points at the canUseTool callback in the SDK harness that spawns workflow subagents.

Impact

  1. The subagent cannot read a single byte, so it produces no analysis.
  2. It exhausts the StructuredOutput retry cap (5) and dies with TelemetrySafeError: StructuredOutput retry cap (5) exceeded.
  3. The parent workflow reports every agent as failed after substantial token spend.

Secondary risk worth flagging: a workflow that post-processes verdicts can silently mislabel these failures. In our case an earlier script bucketed findings with !result.verdict?.isReal, so agents that died this way were reported as "refuted" — i.e. actively dismissed as non-issues — rather than "unverified". Notably, the subagents themselves handled this correctly: they attempted to return rationale: "UNVERIFIED due to tool failure; not a refutation", but that call was itself blocked by this bug, so the honest signal never escaped.

Suggested fix

In the subagent permission path, ensure updatedInput is assigned the inner tool-input payload rather than the permission-decision wrapper — and consider failing loudly if updatedInput does not validate against the tool schema, instead of forwarding it to the tool.

Reproduction notes

Not reliably reproducible on demand due to the intermittency. Occurs with Workflow running ~12 concurrent subagents, each using agent(prompt, { schema }) with a JSON Schema containing required and additionalProperties: false.

Claude Model

Other

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

Claude Code 2.1.220

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

_No response_

View original on GitHub ↗

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