[BUG] ReportFindings tool description overrides a caller-defined subagent output contract; parent gets []

Status Open
Reported on v2.1.233
Maintainer reply None cached
Activity 0 comments · opened Aug 15, 2026

What's wrong

ReportFindings is injected into Agent/Task subagents. Its description, verbatim:

Report code-review findings as a typed list so the host UI can render them. Use this only when the active code-review instructions tell you to report findings with this tool; otherwise follow whatever output format those instructions specify. When reporting a review's results, call it once with the verified findings ranked most-severe first (empty array if nothing survived verification) and do not also print the findings as text.

The last sentence contradicts the only channel a parent has: the subagent's final message text. A subagent that obeys it returns nothing the parent can read. [] is a valid “no findings” result for many callers, so this is silent data loss, not an error.

The first sentence defers to the caller. The last sentence is unconditional and sounds higher-precedence. The subagent has no rule for that conflict.

Two extras the description also imports, which the caller did not ask for:

  1. A verification bar (“empty array if nothing survived verification”).
  2. A ranking/severity scheme.

Expected

A caller-defined output contract wins. Host tools that exist for UI rendering do not tell a subagent to suppress the text the parent reads. If the host needs a structured payload, take it in addition to that text, or relay the tool payload to the parent as the subagent result.

Actual

The subagent calls ReportFindings (often with []) and prints nothing useful. The parent treats it as a clean review.

Evidence

Custom review skill. Three parallel reviewer subagents via Agent/Task. Contract: return findings as the text of the final message. That is the only channel. The skill never mentions ReportFindings.

  • 11 review runs through yesterday: no subagent called it.
  • Today, 2 of 2 runs: the edge-case reviewer called ReportFindings with an empty array and returned [] as its message, after ~7 minutes of real investigation.
  • Claude Code 2.1.233 in both periods. Same client, behavior flipped — consistent with a server-side tool/flag rollout, not a client bump.
  • Resuming that subagent: it denied the tool exists and misdescribed its own toolset. Matches the deferred-tool / resume-rehydration failure in #77146 and the “ToolSearch returns no match” report in #84093.

Minimal reproduction

  1. Start an interactive session (any repo with a real defect is enough).
  2. Confirm ReportFindings is in the catalog (it is, as a built-in / deferred tool).
  3. Spawn a general-purpose subagent via Agent/Task. Prompt, in substance:

> Review <file> for edge cases. Return findings as the text of your final message — a JSON array of {location, trigger_condition} objects. Do not write files. An empty array means you found nothing.

Do not mention ReportFindings. Do not invoke /code-review.

  1. Wait for the subagent to finish. Read the Agent/Task result the parent received, and the subagent transcript (~/.claude/projects/<project>/<session>/subagents/agent-*.jsonl).

Expected: final message is the JSON array. No ReportFindings call.

Actual (when it triggers): a ReportFindings call, often findings: [], and the parent result is [] or empty. Indistinguishable from a clean review.

Trigger is model-choice, not 100%. The 2/2 production hits above are the reliable evidence; the repro is the shape.

Suggested fix

Any one of these closes it; (1)+(3) is the robust pair.

  1. Don't inject ReportFindings into Agent/Task subagents unless the caller opted into that contract (built-in /code-review only, or an explicit flag). This is suggested-fix #4 on #77146, and it would have prevented this.
  2. Rewrite the description so it never says “do not also print the findings as text.” Scope every imperative to “only when the active instructions told you to use this tool.” The current first sentence is not enough; the last sentence overpowers it.
  3. If a subagent does call it, relay the payload to the parent as the subagent result. Never deliver a bare [] / empty string that is also the caller’s legitimate “no findings” token.
  4. Do not import a verification bar into a tool that non-/code-review agents can see.

Related (not duplicates)

  • #77146 — same leak; symptom is a 400 on resume, not silent [].
  • #84093 — inverse: /code-review wants the tool and the background agent doesn't have it.
  • #75559 — same class (leaked return-channel tool swallows the text the parent reads); different tool (StructuredOutput) and path (context: fork).
  • #86070 — same class (two competing output-channel instructions, silent loss); teammate/SendMessage mode.
  • #83516 — /code-review presentation. A comment there already documents that Anthropic ships a fallback contract that says “Do not call the ReportFindings tool even if it is available” — i.e. the tool’s presence is known to be magnetic.

Environment

  • Claude Code 2.1.233
  • macOS
  • Interactive CLI
  • Custom skill spawning Agent/Task reviewer subagents; not /code-review

View original on GitHub ↗