WebSearch always fails with a 400 when effort is set to xhigh
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
- Put
"effortLevel": "xhigh"and"model": "opus[1m]"in~/.claude/settings.json - 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 refusexhighandmaxwithout 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.
Showing cached comments. Read the full discussion on GitHub ↗
4 Comments
Confirmed on macOS (darwin arm64), Claude Code 2.1.219, first-party API, main model
claude-opus-5. Deterministic repro:The tool result is the raw 400; no search results are returned. The identical command with main model
claude-fable-5succeeds atxhigh, consistent with the model matrix in #80995 (in that matrix, Opus 5 is the only model that rejectsxhighon 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:From v2.1.182 it is unconditional in every version sampled, while effort is still attached:
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
xhighwithout 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:
This error message matches neither branch (
output_config.effort≠effort parameter; noextra 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/maxeffort 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:restores WebSearch (verified: Opus 5 main loop at
xhigh→ dispatch this agent → search succeeds), and the session keepsxhigheverywhere 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.)
Adding a measurement that narrows this: the failure is model-dependent, and
claude-sonnet-5does 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: xhighin~/.claude/settings.json, nothinkingkey 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: mediumpin |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, soclaude-sonnet-5should fail too. Per the/v1/modelscapability payload both models look identical on exactly the fields involved:So either sonnet-5 accepts
xhighwith 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:
tool_resulterror, 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 successfulclaude-opus-5@xhigh calls while WebSearch 400'd).maxdoes not followxhighacross the model list:claude-opus-4-6andclaude-sonnet-4-6reporteffort.max.supported=truewitheffort.xhigh.supported=false. Any guard phrased as "effort ≥ xhigh" would mis-handle those.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 whensettings.jsonhas anenvblock.env.CLAUDE_CODE_EFFORT_LEVELoutranks both the shell environment and the--effortflag, 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| stillmax| 400 ||
claude --effort high| stillmax| 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
xhighand--effort maxon the command line, the error names'xhigh'— the env value won, not the flag. The only override that changed the applied effort was--settingscarrying anenvkey.2. Two negative results, both consistent with the
tool_choiceexplanation in the issue body, recorded so others don't spend time retesting them:CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING=1does not help — thinking is off because of the forced tool choice, not because of adaptive thinking.ANTHROPIC_SMALL_FAST_MODELdoes 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.
Confirmed on Windows, native install — adding a platform datapoint plus two things I did not see covered above.
Environment
~/.local/bin/claude.exe, binary dated 2026-07-27)claude-opus-5, first-party API, no gateway (ANTHROPIC_BASE_URLempty)~/.claude/settings.json:"effortLevel": "xhigh","model": "Opus"Same signature, every WebSearch call:
1.
alwaysThinkingEnabled: trueis not a workaround on Opus 5Worth stating explicitly, since #79798 frames the missing
thinking: {type: "adaptive"}translation as the remedy. Setting it changes nothing here:"alwaysThinkingEnabled": trueadded to~/.claude/settings.json→ no effect/reload-plugins→ no effect (loads plugins/skills/hooks, not model config)/fast) → no effectmanaged-settings.jsonin any policy location, no thinking/effort keys in~/.claude.jsonorsettings.local.json, noMAX_THINKING_TOKENSin the environmentThis 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
xhighI 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
/bugand/feedbackare disabled whenCLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1is set: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
xhighfail the same way, which takes out WebSearch across whole multi-agent workflows, not just interactive use.WebFetchagainst 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.