You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Two related problems observed in real use on 1.0.169 with Claude Code.
A deny or nudge issued for one tool in a parallel tool batch competes with the successful results of its sibling calls, and reliably loses. The model consumes whatever succeeded and never follows the redirect.
The WebFetch deny has no opt-out, unlike every other routing behavior.
The first is the more interesting one, because in the observed case context-mode did not save context. It degraded the answer.
What happened
The task was to check whether Google Geocoding's components filter and bounds viewport biasing are compatible. The model emitted two calls in a single parallel block:
WebFetch on the official Google docs page
WebSearch for the same question
WebFetch was denied with the standard redirect reason (call ctx_fetch_and_index, then ctx_search). WebSearch succeeded and returned blog-grade summaries of the same documentation.
Both results arrived together. The model read the search results, answered from them, and never called ctx_fetch_and_index. The suggested path was not refused, it was simply never reached: by the time the deny was visible, an alternative answer was already in hand.
Net effect:
The authoritative source (the official docs) was the one thing that got blocked.
A lower-quality secondary source was substituted silently.
No bytes were saved, because WebSearch output entered the context window anyway.
The redirect's bytesAvoided: 16384 accounting recorded a saving that did not occur, since the model still ingested comparable content from the sibling call.
The answer happened to survive only because the claim was independently verified against the live API afterwards. Without that, a documentation claim would have been reported without the documentation ever being read.
Why this is structural, not a one-off
The redirect reason is written as though it is the only signal the model receives:
In a serial flow that holds: the deny is the only new information, so the model acts on it. In a parallel batch the deny is one entry among several, and it is the only unsuccessful one. Models resolve that by using what worked. Any guidance whose efficacy depends on being the sole signal is fragile in exactly the batches that agents are encouraged to emit for latency.
This likely affects the Bash / Read / Grep nudges too, though the effect is milder there because those are advisory rather than a hard deny.
Second problem: no opt-out for the WebFetch deny
hooks/core/routing.mjs:874-887 returns action: "deny" for WebFetch unconditionally. There is no env guard, in contrast to the knobs that exist elsewhere in the same file:
CONTEXT_MODE_BASH_NUDGE_MIN_COMMAND_BYTES
CONTEXT_MODE_EXTERNAL_MCP_NUDGE_EVERY
CONTEXT_MODE_REQUIRE_SECURITY
CONTEXT_MODE_SUPPRESS_SECURITY_WARNING
WebFetch is the strongest intervention in the routing table and the only one with no switch. A user who wants to keep the Bash/Read/Grep nudges but drop the WebFetch deny has to delete the "matcher": "WebFetch" block from hooks/hooks.json inside the versioned cache directory (.../context-mode/<version>/hooks/), which an upgrade silently reverts.
Suggestions
Add an opt-out, e.g. CONTEXT_MODE_DISABLE_WEBFETCH_REDIRECT=1, consistent with the existing CONTEXT_MODE_* conventions. Cheapest fix, independent of the rest.
Make the reason batch-aware. Add an explicit line: results from other tools in this same batch do not satisfy this request; retry this URL via ctx_fetch_and_index before continuing. Models follow explicit negative instructions here better than implied ones.
Close the loop in PostToolUse. A redirect is already tagged with redirectMeta.type = "webfetch-redirected" and the URL. If no ctx_fetch_and_index for that URL follows within N tool calls, re-inject the nudge. That converts a one-shot suggestion into something observable, and would also make the bytesAvoided accounting honest, since a redirect that was never followed avoided nothing.
Summary
Two related problems observed in real use on
1.0.169with Claude Code.denyor nudge issued for one tool in a parallel tool batch competes with the successful results of its sibling calls, and reliably loses. The model consumes whatever succeeded and never follows the redirect.WebFetchdeny has no opt-out, unlike every other routing behavior.The first is the more interesting one, because in the observed case context-mode did not save context. It degraded the answer.
What happened
The task was to check whether Google Geocoding's
componentsfilter andboundsviewport biasing are compatible. The model emitted two calls in a single parallel block:WebFetchon the official Google docs pageWebSearchfor the same questionWebFetchwas denied with the standard redirect reason (callctx_fetch_and_index, thenctx_search).WebSearchsucceeded and returned blog-grade summaries of the same documentation.Both results arrived together. The model read the search results, answered from them, and never called
ctx_fetch_and_index. The suggested path was not refused, it was simply never reached: by the time the deny was visible, an alternative answer was already in hand.Net effect:
WebSearchoutput entered the context window anyway.bytesAvoided: 16384accounting recorded a saving that did not occur, since the model still ingested comparable content from the sibling call.The answer happened to survive only because the claim was independently verified against the live API afterwards. Without that, a documentation claim would have been reported without the documentation ever being read.
Why this is structural, not a one-off
The redirect reason is written as though it is the only signal the model receives:
In a serial flow that holds: the deny is the only new information, so the model acts on it. In a parallel batch the deny is one entry among several, and it is the only unsuccessful one. Models resolve that by using what worked. Any guidance whose efficacy depends on being the sole signal is fragile in exactly the batches that agents are encouraged to emit for latency.
This likely affects the
Bash/Read/Grepnudges too, though the effect is milder there because those are advisory rather than a harddeny.Second problem: no opt-out for the WebFetch deny
hooks/core/routing.mjs:874-887returnsaction: "deny"forWebFetchunconditionally. There is no env guard, in contrast to the knobs that exist elsewhere in the same file:CONTEXT_MODE_BASH_NUDGE_MIN_COMMAND_BYTESCONTEXT_MODE_EXTERNAL_MCP_NUDGE_EVERYCONTEXT_MODE_REQUIRE_SECURITYCONTEXT_MODE_SUPPRESS_SECURITY_WARNINGWebFetchis the strongest intervention in the routing table and the only one with no switch. A user who wants to keep the Bash/Read/Grep nudges but drop the WebFetch deny has to delete the"matcher": "WebFetch"block fromhooks/hooks.jsoninside the versioned cache directory (.../context-mode/<version>/hooks/), which an upgrade silently reverts.Suggestions
CONTEXT_MODE_DISABLE_WEBFETCH_REDIRECT=1, consistent with the existingCONTEXT_MODE_*conventions. Cheapest fix, independent of the rest.ctx_fetch_and_indexbefore continuing. Models follow explicit negative instructions here better than implied ones.redirectMeta.type = "webfetch-redirected"and the URL. If noctx_fetch_and_indexfor that URL follows within N tool calls, re-inject the nudge. That converts a one-shot suggestion into something observable, and would also make thebytesAvoidedaccounting honest, since a redirect that was never followed avoided nothing.guidanceOncefor WebFetch, asGrepalready does, or make the severity configurable. A hard deny on the only authenticated fetch path is a large hammer, and WebFetch redirect has no exemption for claude.ai/code/artifact URLs, breaks artifact fetches #984 is another case where the unconditional deny removes capability with no workaround.Related: #984 (WebFetch deny has no exemption for
claude.ai/code/artifactURLs). Same unconditional branch, different symptom.Filed from a Claude Code session where this occurred; the transcript detail above is the actual observed behavior, not a reconstruction.