[BUG] Every Opus subagent dies at 0 tokens on xhigh effort — spawn path hard-sets thinking:{type:"disabled"} while still sending effort:xhigh

Status Closed — not planned
Reported on v2.1.220
Maintainer reply None cached
Activity 1 comment · opened Aug 3, 2026 · closed Aug 3, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code (see note on version below)

What's Wrong?

On claude-opus-5, when the session effort is xhigh, every subagent spawned through the Task/Agent tool dies instantly:

API Error: 400 output_config.effort 'xhigh' is not supported when thinking is disabled on this model. Use effort 'high' or below, or enable thinking.

The subagent does zero work — subagent_tokens: 0, tool_uses: 0, duration_ms: 384. The main conversation loop is unaffected, because it sends thinking enabled.

This is the subagent instance of the effort/thinking-coupling family (#81084, #79798, #76689, #80940, #83364, #80995). It is not covered by those reports — two of them explicitly state subagents are not affected for their reporters (#76689: "0 events in subagent transcripts — subagents never hit this"; #79798: "Main-loop turns and subagents continue to work"). #68797 covered the subagent path but for a different error string (thinking.disabled.display) and is closed.

Root cause (from the shipped bundle)

Two independent code paths disagree about whether thinking is on.

1. The subagent spawn path hard-disables thinking unless a server-side rollout flag is on:

thinkingConfig: W || !1 || OP8(F) ? q.options.thinkingConfig : {type:"disabled"}

OP8 resolves a server-delivered gate keyed by model name:

function OP8(H){
  let $ = S$().clientDataCache?.cedar_lagoon;
  if (typeof $ !== "object" || $ === null) return !1;
  let q = WK(H);
  return Object.entries($).some(([K,_]) => _ === !0 && q.includes(K))
}

With that gate off (the default), the subagent request always carries thinking: {type: "disabled"} — regardless of the parent session's thinking config.

2. The effort applier never looks at thinking:

function ttf(H,$,q,K,_){
  if(!kP(_)){ delete $.effort; return }   // only checks: does the model support effort at all
  if("effort" in $) return;
  if(H === void 0) K.push(ecH);
  else if(typeof H === "string") $.effort = H, K.push(ecH)
}

kP(model) is "model supports effort", not "this effort level is legal given the current thinking state". So output_config.effort: "xhigh" is attached to a request that path 1 just gave thinking: {type:"disabled"}, and the API rejects the combination.

Effort and thinking are coupled at the API boundary but set independently, in two places that never consult each other.

What Should Happen?

Either:

  1. The subagent spawn path should inherit the parent's thinking config (or enable adaptive thinking) when effort is xhigh/max; or
  2. The effort applier should clamp effort to high whenever the outgoing request has thinking.type === "disabled" — the API's own error text names this as the fix.

Option 2 also repairs the WebSearch/WebFetch variants in the linked issues, since those call sites hard-disable thinking the same way. Related: #80995 notes an effort-downgrade retry already exists but its matcher doesn't catch this error string.

Whatever the fix, this should not fail silently. A dispatch that dies at 0 tokens in under a second is easy to miss.

Steps to Reproduce

  1. Use model claude-opus-5. Leave effort at the default, or set "effortLevel": "xhigh" in ~/.claude/settings.json.
  2. Restart, confirm the session is at xhigh (/effort).
  3. Spawn any subagent with no model override:

> Use the Agent tool with subagent_type "general-purpose" and prompt "Reply with exactly: PONG. No tools."

  1. It fails immediately with the 400 above.

Model matrix — same session, same xhigh effort, only the model override changed:

| Agent model | Result | tokens | duration |
|---|---|---|---|
| (none — inherits opus-5) | 400 thinking-disabled | 0 | 384 ms |
| fable | OK | 29,398 | 5,072 ms |
| sonnet | OK | 20,092 | 1,932 ms |
| haiku | OK | 20,288 | 1,447 ms |

Fable 5 is immune because its adaptive thinking cannot be disabled, consistent with #79798.

Impact

The Agent tool is completely non-functional at xhigh, and it fails quietly. A /review run lost all four specialist subagents (testing, maintainability, security, performance) and would have reported a clean review with no indication the specialists never ran. The same exposure applies to any skill that fans out to subagents and to the Workflow tool, which spawns through this path.

Things that do NOT work as workarounds

  • MAX_THINKING_TOKENS — read at startup into the session thinking config, but the subagent ternary discards it. Independently confirmed in #68797.
  • alwaysThinkingEnabled: true — same reason for subagents; also reported ineffective for the main loop in #76689 / #79798.
  • A settings.json env block setting CLAUDE_EFFORTCLAUDE_EFFORT is write-only. Claude Code exports it to Bash/hook children as a readout of the current turn's effort; process.env.CLAUDE_EFFORT is never read back. Worth documenting, since its presence in env output reads like a cause and sends people hunting for an injection that doesn't exist.
  • Per-agent effort: frontmatter — ignored (#64706).
  • Upgrading — #81084 reproduces on 2.1.220.

The only working fix is "effortLevel": "high", which also drops the main loop from xhigh. Passing an explicit non-Opus model: works per-call but doesn't help skills or Workflow, which spawn without one.

Environment Info

  • Version: 2.1.170 (Claude Desktop app, Linux; CLAUDE_CODE_ENTRYPOINT=claude-desktop). The linked issues confirm the same family reproduces on 2.1.205–2.1.220, and #81084 is on 2.1.220.
  • SDK: 0.3.170
  • Platform: Linux 6.17.0-1030-oem
  • Model: claude-opus-5
  • Subscription, direct Anthropic connection (no gateway)
  • ~/.claude/settings.json had no effortLevel, no env block, no alwaysThinkingEnabled — the session was at xhigh by default for this model
  • CLAUDE_CODE_EFFORT_LEVEL unset

Claude Model

Claude Opus 5

View original on GitHub ↗

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