WebSearch always fails with a 400 when effort is set to xhigh

Status Fixed / completed
Reported on v2.1.219
Maintainer reply None cached
Activity 5 comments · opened Jul 24, 2026 · closed Aug 20, 2026

What happens

Set effort to xhigh, then run any WebSearch. It fails every time:

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.

Every other tool works in the same session. WebFetch, Bash, Read and Edit all run fine. Only WebSearch fails. Subagents that inherit xhigh from an agent file fail the same way.

Steps to reproduce

  1. Put "effortLevel": "xhigh" and "model": "opus[1m]" in ~/.claude/settings.json
  2. Run any WebSearch query

Why it happens

WebSearch does not hand the query straight to the search tool. It makes its own API request, and that request sets thinking to disabled, because it forces tool_choice to web_search and a forced tool choice needs thinking off.

The code that adds output_config.effort then adds it anyway. It checks whether the model supports effort at all, but not whether thinking is off. Opus 5 refuses xhigh and max when thinking is off, so the request fails.

There is a second problem behind it. The CLI already has a retry that drops effort and tries again when a model refuses it. That check matches only two wordings:

  • "effort parameter" plus "not support"
  • "output_config" plus "effort" plus "extra inputs are not permitted"

The error above matches neither, so the retry never runs and the raw 400 lands in the tool result.

What I expected

WebSearch should work whatever the effort setting. A user cannot reach the thinking field of an internal request, so the only way out today is to drop the whole session to high.

Suggested fix

  • When thinking is off, cap effort at high, or leave it out, for models that refuse xhigh and max without thinking.
  • Widen the retry check to match "not supported when thinking is disabled", so the drop-and-retry path covers this case too.

Version

2.1.219 on Linux, model claude-opus-5. Not new to this release. It has failed since late June.

View original on GitHub ↗

4 Comments

willmcginnis · 1 month ago

Confirmed on macOS (darwin arm64), Claude Code 2.1.219, first-party API, main model claude-opus-5. Deterministic repro:

# with "effortLevel": "xhigh" in ~/.claude/settings.json
claude -p 'Call the WebSearch tool once with query "anthropic claude code" and report the result.' \
  --model claude-opus-5 --allowedTools WebSearch
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 tool result is the raw 400; no search results are returned. The identical command with main model claude-fable-5 succeeds at xhigh, consistent with the model matrix in #80995 (in that matrix, Opus 5 is the only model that rejects xhigh on a thinking-disabled request).

Two data points to add, from bisecting the native-install release binaries (darwin-arm64, classifying the WebSearch sub-request construction in each bundle):

1. The unconditional thinking-disable shipped in v2.1.182 (built 2026-06-18).

Through v2.1.181, the sub-request only disabled thinking (and only forced tool_choice) on the gated small-model path — the default was the main-loop model with the session's thinking config:

// v2.1.181 (2026-06-17) — conditional on the tengu_plum_vx3 gate (default off)
thinkingConfig: c ? {type:"disabled"} : t.options.thinkingConfig,

From v2.1.182 it is unconditional in every version sampled, while effort is still attached:

// v2.1.182 (2026-06-18); same shape in 2.1.185, 2.1.190, 2.1.216, 2.1.219
thinkingConfig: {type:"disabled"},
...
model: p,                                    // main-loop model unless tengu_plum_vx3
toolChoice: {type:"tool", name:"web_search"},
...
effortValue: ...                             // session effort, regardless of thinking state

Bisect: 2.1.143 conditional → 2.1.172 conditional → 2.1.181 conditional → 2.1.182 unconditional → 2.1.185 → 2.1.190 → 2.1.216 → 2.1.219 all unconditional. That matches the OP's "It has failed since late June": the shape shipped June 18, and it bites once the main model is one that rejects xhigh without thinking.

2. The retry-classifier gap is confirmed in the 2.1.219 darwin bundle — same finding as #80995. The effort-unsupported recovery is gated on:

if (t.includes("effort parameter") && t.includes("not support")) return !0;
return t.includes("output_config") && t.includes("effort") && t.includes("extra inputs are not permitted")

This error message matches neither branch (output_config.efforteffort parameter; no extra inputs are not permitted), so the existing drop-effort-and-retry never fires and the raw 400 lands in the tool result.

Both layers of the fix suggested in the OP look right to me: don't attach xhigh/max effort to a sub-request that hard-disables thinking, and widen (or structurally key) the retry classifier so a new server phrasing can't silently disable the recovery.

Workaround that doesn't require dropping the whole session to high: route searches through a subagent whose definition pins a tolerated effort — the sub-request inherits the agent's effort instead of the session's. An agent file like:

---
name: search-high-effort
description: Web-search lane; effort pinned to high so WebSearch works on Opus 5 while the session stays at xhigh
model: inherit
effort: high
tools: WebSearch, WebFetch
---

restores WebSearch (verified: Opus 5 main loop at xhigh → dispatch this agent → search succeeds), and the session keeps xhigh everywhere else.

Related: #80995 (same classifier gap, WebFetch via the haiku-slot model), #76689, #79798.

(Investigation done in Claude Code itself — binary analysis of the minified darwin bundles.)

lunetics · 1 month ago

Adding a measurement that narrows this: the failure is model-dependent, and claude-sonnet-5 does not reproduce it at the same effort on the same code path.

All four cells below ran the same day, same session, same query (allowed_domains: ["home-assistant.io"]), Claude Code 2.1.219, effortLevel: xhigh in ~/.claude/settings.json, no thinking key anywhere:

| Path | Effective model | Effort | WebSearch |
|---|---|---|---|
| main loop | claude-opus-5 | xhigh | 400 |
| subagent, no effort: pin (inherits) | claude-opus-5 | xhigh | 400 |
| subagent, no effort: pin (inherits) | claude-sonnet-5 | xhigh | succeeds, 10 results |
| subagent with effort: medium pin | claude-sonnet-5 | medium | succeeds |

Effective model and effort were read from the subagent transcripts (message.model, "effort":"xhigh"), not inferred from the inheritance rule. The two subagent rows used the same agent definition — only the model differs — so path and effort are held constant.

This is hard to square with "WebSearch forces tool_choice, so thinking is off, and effort is added anyway": that mechanism is model-independent, so claude-sonnet-5 should fail too. Per the /v1/models capability payload both models look identical on exactly the fields involved:

claude-opus-5    effort.xhigh.supported=true  thinking.types.enabled.supported=false  adaptive=true
claude-sonnet-5  effort.xhigh.supported=true  thinking.types.enabled.supported=false  adaptive=true

So either sonnet-5 accepts xhigh with thinking off while opus-5 rejects it (server-side difference not visible in the capability payload), or the sub-request is not built identically for the two. Might be worth checking before fixing only the client-side guard.

Two smaller notes:

  • The 400 arrives as a tool_result error, not a turn-level API error — the session keeps running normally, only the tool call dies. Consistent with the sub-request analysis in the issue body, and it means the session's own effort/thinking pair is demonstrably valid (this session made hundreds of successful claude-opus-5@xhigh calls while WebSearch 400'd).
  • max does not follow xhigh across the model list: claude-opus-4-6 and claude-sonnet-4-6 report effort.max.supported=true with effort.xhigh.supported=false. Any guard phrased as "effort ≥ xhigh" would mis-handle those.
hillimited · 1 month ago

Three measurements not yet in this thread, from 2.1.220 / claude-opus-5 / macOS (darwin arm64), first-party API.

1. The "drop to high" workaround silently fails when settings.json has an env block.

env.CLAUDE_CODE_EFFORT_LEVEL outranks both the shell environment and the --effort flag, so the usual ways of lowering effort for a single session do nothing and the identical 400 comes back. It reads as "lowering effort doesn't fix it" when in fact the effort never changed.

| Attempt | Effort actually applied | WebSearch |
|---|---|---|
| CLAUDE_CODE_EFFORT_LEVEL=high claude | still max | 400 |
| claude --effort high | still max | 400 |
| --settings '{"env":{"CLAUDE_CODE_EFFORT_LEVEL":"xhigh"}}' --effort max | xhigh | 400 |
| --settings '{"env":{"CLAUDE_CODE_EFFORT_LEVEL":"high"}}' | high | OK |

Row 3 is the diagnostic one: with the env value at xhigh and --effort max on the command line, the error names 'xhigh' — the env value won, not the flag. The only override that changed the applied effort was --settings carrying an env key.

2. Two negative results, both consistent with the tool_choice explanation in the issue body, recorded so others don't spend time retesting them:

  • CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING=1 does not help — thinking is off because of the forced tool choice, not because of adaptive thinking.
  • ANTHROPIC_SMALL_FAST_MODEL does not help — the failing request uses the session model, not a separate small/fast one.

3. Still reproducing on 2.1.220; the most recent confirmation above was 2.1.219.

ChristianMLux · 1 month ago

Confirmed on Windows, native install — adding a platform datapoint plus two things I did not see covered above.

Environment

  • Claude Code 2.1.220, native install (~/.local/bin/claude.exe, binary dated 2026-07-27)
  • Windows 11 Pro 10.0.26200, Git Bash shell
  • Model claude-opus-5, first-party API, no gateway (ANTHROPIC_BASE_URL empty)
  • ~/.claude/settings.json: "effortLevel": "xhigh", "model": "Opus"

Same signature, every WebSearch call:

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.

1. alwaysThinkingEnabled: true is not a workaround on Opus 5

Worth stating explicitly, since #79798 frames the missing thinking: {type: "adaptive"} translation as the remedy. Setting it changes nothing here:

  • "alwaysThinkingEnabled": true added to ~/.claude/settings.json → no effect
  • full CLI restart afterwards → no effect
  • /reload-plugins → no effect (loads plugins/skills/hooks, not model config)
  • fast mode off (/fast) → no effect
  • verified absent as a confounder: no managed-settings.json in any policy location, no thinking/effort keys in ~/.claude.json or settings.local.json, no MAX_THINKING_TOKENS in the environment

This is consistent with the root cause in this issue: the sub-request hard-disables thinking regardless of session config, so no user-facing thinking setting can reach it.

2. The main loop is provably unaffected — useful for triage

In one session at xhigh I ran dozens of turns across Bash, Read, Edit, Write, WebFetch, Skill invocations and a long sequence of MCP browser-automation calls. Zero 400s. Only WebSearch fails.

That is a clean negative control: if the session were running with thinking disabled, every main-loop request would carry the same illegal xhigh + thinking-off combination and fail identically. It doesn't — which localises the defect to the WebSearch sub-request construction and rules out session-wide thinking loss on Opus 5. The status line correctly reads "thinking with xhigh effort" throughout.

3. In-product reporting is unreachable in a common config

/bug and /feedback are disabled when CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 is set:

/feedback has been disabled via the CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC environment variable

So anyone hitting this bug with that env var set cannot file from inside the product and has to come to GitHub manually. That likely suppresses the reported incidence of this issue somewhat.

Impact note

Seconding the subagent point from the original report: agents inheriting xhigh fail the same way, which takes out WebSearch across whole multi-agent workflows, not just interactive use. WebFetch against a search endpoint works as a stopgap and returns usable results, so the capability is recoverable — but only if you know to route around it.

Showing cached comments. Read the full discussion on GitHub ↗