WebFetch: prompt-based extraction ignored — full raw page dumped into context, exhausting 1M-token window after 3-4 fetches
Summary
WebFetch (and the Fetch tool used inside background/loop sessions) does not honor its own prompt parameter for extraction. Even when the caller explicitly asks for a narrow, extracted answer (e.g. "extract exactly which model IDs support X"), the tool injects the entire converted page (full Markdown, including every table, <Note>/<Tip> block, and code sample) into the conversation transcript/context. On documentation pages such as docs.claude.com/platform.claude.com, a single page is 20–30 KB of Markdown. Doing 3–4 such fetches in a row — a completely normal pattern when cross-referencing a handful of doc pages — is enough to consume essentially all of a 1,000,000-token context window, derailing the rest of the session.
Environment
- Claude Code version:
2.1.198 - OS: macOS 26.5.2 (BuildVersion 25F84), Darwin 25.5.0
- Model in session:
claude-sonnet-5 - Reproduced in: a background/loop agent session doing multi-source research (fetching Anthropic docs + comparing against OpenAI/Google docs) inside a project with no git commits yet
Steps to Reproduce
- Start a Claude Code session (interactive or background/subagent) on any project.
- Ask it a question that requires checking a handful of
docs.claude.com/platform.claude.compages, e.g.: "Which Claude models support theeffortparameter and which levels does each support?" - Observe Claude issuing
WebFetch/Fetchcalls with a specific, narrowprompt, for example:
````
Fetch(url: "https://platform.claude.com/docs/en/build-with-claude/effort.md",
prompt: "Extract exactly which Claude model IDs support the effort parameter,
which effort levels (low/medium/high/xhigh/max) each supports, and
which models error when...")
- The tool result is logged as
Received 22.2KB (200 OK). - Immediately after, the full page is dumped verbatim into the transcript — starting from the
# Effortheading and continuing through every section (How effort works, the full effort-levels table, every<Note>/<Tip>callout,Effort with extended thinkingper-model bullet list,Best practices,Next steps, etc.) — none of it filtered down to what thepromptasked for. - Repeat for 3–4 pages (in the observed session: the Claude models overview page, the effort.md page, and two more fetched in parallel against OpenAI/Google docs for comparison) and the context is effectively exhausted — a 1,000,000-token window filled after only 3–4 fetches.
Expected Behavior
When a prompt/extraction instruction is supplied to WebFetch, the tool should return a short, targeted extract (ideally on the order of a few hundred to a couple thousand tokens) that answers the prompt — not the raw page. This is the entire point of passing a prompt argument instead of doing a plain fetch: it should behave like a mini sub-agent call that reads the page and returns a distilled answer, similar to how Task/sub-agent results only surface a final summary rather than every tool call's raw output.
Actual Behavior
- The extraction step appears to be skipped or bypassed: the full HTML→Markdown conversion of the page is inserted into context regardless of the
prompt. - This happened consistently across every fetch observed in the session (screenshots 1, 2, 3, 4, 6 all show large, unfiltered Markdown dumps — headings, full code samples in Python/TypeScript/C#, full
<Note>blocks, full tables — fromdocs.claude.com/platform.claude.compages). - Screenshot 4 is the clearest evidence: it shows the actual
Fetch(...)invocation with itspromptargument on one line, followed byReceived 22.2KB (200 OK), followed immediately by the complete, un-summarized document body. - Because the research task legitimately required checking multiple pages (and even ran 4 fetches in parallel to cross-reference Anthropic's
effortdocs against OpenAI'sreasoning_effortand Google'sthinking_levelequivalents), context filled up almost immediately, well before the actual coding task could proceed.
Impact
- Makes any multi-page research/verification task (a common and encouraged pattern — "don't guess, verify against live docs") prohibitively expensive in context, even on a 1M-token model.
- Defeats the purpose of the
promptparameter entirely — if it doesn't reduce what lands in context, there's no reason to pass it vs. a bare fetch. - Forces users/agents to either avoid
WebFetchfor anything beyond a single quick lookup, or to burn most of the context budget on raw HTML-derived Markdown instead of on the actual task. - Particularly bad for background/subagent sessions doing autonomous verification loops, where several fetches per iteration is the normal shape of the work.
Suspected Root Cause
Likely one of:
- The
promptis being sent to the underlying fetch/convert step but the extraction/summarization sub-call that should condense the page against that prompt is not actually running (or its output is discarded and the raw converted content is returned instead). - There's a size threshold under which the tool short-circuits straight to "return raw content" without ever invoking extraction, and typical doc pages (20–30 KB) fall under it.
- The extraction step runs, but its result is being displayed/appended in addition to the raw page rather than replacing it in the transcript that becomes context.
Suggested Fixes
- Guarantee that when a
promptis supplied, only the model-produced extract (not the raw fetched content) is returned as the tool result — enforce this at the tool-result-construction layer, not just as a best-effort instruction to an inner model call. - Add a hard cap on how many tokens a single
WebFetchresult can inject into context (e.g. a few thousand tokens), truncating/summarizing server-side before it ever reaches the caller's context, with a clear "truncated — N KB total, use a more specific prompt or fetch a sub-section" notice. - Where no
promptis given, still consider returning a capped/paginated result (mirroringRead'soffset/limitpattern) rather than the full page, so a plain fetch of a large doc can't alone eat hundreds of thousands of tokens. - Surface an estimated token count for the fetched content before/along with injecting it into context, so the acting model can decide whether to proceed, narrow the prompt, or fetch a smaller section.
- Consider de-duplicating repeated fetches of the same URL within a session/run.
Related observation (possibly a separate issue)
In the same session, an EnterWorktree call failed with Failed to resolve base branch "HEAD": git rev-parse failed because the target repo had no commits yet, and the background session then blocked a subsequent Write with: "This background session hasn't isolated its changes yet. Call EnterWorktree first so edits land in a worktree instead of the shared checkout..." — i.e., background-session isolation has no fallback for a repo with zero commits, forcing the agent to either fail or write directly to the shared checkout. Flagging this in case it's useful, but happy to file it separately if preferred.
4 Comments
Full disclosure: I maintain cozempic.
The root cause you've documented belongs squarely with CC — when a
promptis supplied, only the extract should land in context, not the raw converted page. Your suggested fix is the right shape.While that's pending: those 20–30 KB Markdown dumps land as full-size
tool_resultblocks in the session JSONL and inflate every subsequent turn's context cost, not just the turn they were fetched in. cozempic'stool-output-trimstrategy truncates oversized tool result blocks across the session file, so you're not paying the overhead from an early research pass for the rest of the task.It won't fix the underlying fetch-dumps-everything bug, and it's a post-hoc step rather than a preventive one — but it can rescue a session that's already been hit by a multi-page research pass, trimming the inflated payloads down so the actual coding work can continue without
/clear.This thread is a WebFetch bug report, not a place to pitch a tool. Before recommending
cozempic, consider the actual fix instead of a post-hoc cleanup around the symptom.By your own description it doesn't touch the root cause — it just rewrites the session JSONL after the raw dumps already landed. That's not a solution here, it's a workaround that adds its own risks: the package auto-updates from PyPI daily and in-place by default and ships telemetry on by default, while editing files that can contain tokens and secrets. Recommending that as a fix for a context-bloat bug moves the problem, it doesn't close it.
If you want to help this issue: the fix belongs at the tool-result-construction layer — when a
promptis supplied, return only the extract, and cap what a single fetch can inject. If you have a patch for that, that's worth posting. A plug for a session-file editor isn't.@mytler you're right on the main point — the fix belongs at the tool-result construction layer, and I should have been clearer that what I was describing is a workaround around the symptom, not a solution to the bug. Fair criticism.
On the specific risks you raised, since you called them out by name and others may be reading:
Auto-updates: accurate that cozempic auto-updates by default. It can be disabled with
COZEMPIC_NO_AUTO_UPDATE=1in the environment, or avoided entirely by pinning a version viapipx install cozempic==<version>. Worth disclosing explicitly — I didn't in my original comment.Telemetry: also accurate that it's on by default.
COZEMPIC_NO_TELEMETRY=1disables it. What's sent is session statistics (token counts, compression ratios, strategy results) — not session content. But "on by default" is a fair point to flag.Editing files that may contain secrets: the tool-output-trim strategy truncates the tail of oversized tool-result text blocks (the raw content string inside the JSONL entry) rather than extracting or routing them anywhere — but the concern about anything touching those files is reasonable and I should have been explicit about the trust model.
The underlying WebFetch bug — full raw page dumped into context when a prompt is supplied — is the right thing to fix. If you or anyone has a patch for the tool-result construction side, that's a better outcome than a session-file workaround.
Reproduced on 2.1.233 (Linux): asking WebFetch for a narrow extraction from
https://platform.claude.com/docs/en/build-with-claude/effort.mdreturned the entire ~22.6 KB page verbatim as the tool result — the extraction prompt was not applied. A control fetch of a large HTML page (~600 KB raw) returned a short extracted answer, so extraction does run in general.This is intended behavior, though we agree it's confusing and underdocumented: for the built-in pre-approved documentation domains, when the server returns Markdown directly and the page is under a fixed size cap (~100 KB), WebFetch returns the raw Markdown verbatim instead of running the extraction model. This trades context for fidelity — the extraction pass is lossy, and for trusted docs the exact tables and IDs are usually what you want. Bisecting public npm releases, the behavior has existed since v2.0.41, so it's not a recent regression.
One correction: pages on this path are capped at ~100 KB (~25K tokens), and your example page is ~22 KB (~6K tokens), so 3–4 such fetches can't by themselves exhaust a 1M-token window — though many fetches in a long research loop do add up.
We're considering documenting this exception explicitly and whether to honor the prompt (or offer an opt-in to extraction) for these pages. Leaving open as a design/docs-clarity issue.
🤖 Generated with Claude Code