Accumulated inline image base64 in session history causes 'Request too large (max 20MB)' — blocks all messages including /feedback
Bug Description
Getting \Request too large (max 20MB). Double press esc to go back and try with a smaller file.\ error on text-only follow-up messages after prior inline screenshots have accumulated in the conversation history. The error also blocks submitting \/feedback\, making it difficult to report the issue when it occurs.
Suspected regression, reproduced on v2.1.91. The error was not observed between 2026-03-07 and 2026-04-03 across dozens of sessions on this machine. Historical search across all local Claude Code sessions shows only 3 affected sessions: one on 2026-03-07 and two on 2026-04-03. Note: absence from the changelog between v2.1.73–v2.1.91 does not prove no regression shipped — it only means none was documented.
Probable Root Cause (Session Forensics — Not Confirmed by Anthropic)
Inline image blocks (pasted/attached screenshots) are persisted as base64 in conversation history and re-sent with every subsequent API call. Once enough images accumulate, the serialized request exceeds the 20MB per-request cap — then every future message fails, even pure text ones with zero images.
Key forensic evidence (from independent Codex CLI audit of the affected session JSONL):
- First \
Request too large\error occurred at JSONL line 356 - First screenshot \
Read\call did not occur until JSONL line 390 — the \Read\tool was NOT the initial trigger - At first failure: 14 inline image blocks with ~35.8M base64 characters already in history
- Total session: 25 inline image blocks with ~55.2M base64 characters
- Local image cache: 31 files totaling 52.6MB
Additional behavioral observations:
- Even after \
/rewind\, the base64 from previously-sent images persists in conversation state — text-only prompts still carry the accumulated image payload - Initially, providing file paths (which triggers the \
Read\tool) caused the error, while providing file URLs did not — but eventually even URLs stopped working - The error compounds: each \
/rewind\gives temporary relief but the underlying payload remains - The user was on a 1M-context model (Opus 4.6) at only 41% utilization (~409K tokens) — the 20MB wire-size cap is hit long before the semantic token limit
Prior Image-Related Fixes (Release Notes)
| Version | Release Date | Change |
|---------|-------------|--------|
| v1.0.28 | Pre-2026 | "Resizes images before upload to prevent API size limit errors" |
| v2.1.37 | Feb 7, 2026 | "Stripping images before sending to the compaction API" (#26188) |
| v2.1.43 | ~Feb 2026 | "Fixed image dimension limit errors to suggest /compact" |
| v2.1.71 | Mar 7, 2026 | "Fixed the Read tool putting oversized images into context when image processing failed" |
| v2.1.72 | Mar 10, 2026 | "Fixed oversized and truncated images from Bash data-URL output" |
The v2.1.71/v2.1.72 fixes addressed specific edge cases (Read tool failure path + Bash data-URL), but did not implement a general 20MB pre-flight payload size check or image pruning from accumulated conversation history.
Steps to Reproduce
- Start a Claude Code session (v2.1.91, Opus 4.6 1M context, Max subscription 20x)
- Paste or attach several screenshots/images during the conversation (inline, not necessarily via \
Read\tool) - Continue working — the base64 of each image persists in conversation history
- After enough images accumulate (~14+ Retina screenshots = ~35MB base64), the serialized request exceeds 20MB
- Every subsequent message — including pure text with no images — fails with \
Request too large (max 20MB)\ - \
/feedback\was not a reliable escape hatch during the failure state - \
/rewind\gives temporary relief but the error recurs since image data remains in history - Providing file paths (\
Read\tool) vs file URLs behave differently initially, but both eventually fail
Expected Behavior
- Inline image data should be pruned, cached by reference, or excluded from re-serialization after initial processing
- If re-sending is necessary, auto-compact should trigger before the 20MB cap
- The error message should say "conversation payload too large" not "try with a smaller file"
- \
/feedback\should always work regardless of conversation size - A 1M-context model should not hit a 20MB serialization wall at 41% token utilization
Session Evidence
| Date | Session | Role | Notes |
|------|---------|------|-------|
| 2026-03-07 | ec29e14c | Affected | First observed occurrence (14 error instances in JSONL) |
| 2026-03-08 to 2026-04-02 | (none) | — | ~4 weeks with no occurrences across many sessions |
| 2026-04-03 | 0d396357 | Primary affected session | 28 error instances, 14 inline images before first failure, 25 total |
| 2026-04-03 | 8a545e48 | Follow-up investigation | Session used to file this issue and research the bug (not independent repro) |
Environment
- Claude Code: v2.1.91 (released Apr 2, 2026)
- Subscription: Claude Max (20x)
- Model: Opus 4.6 (1M context window)
- macOS: Darwin 25.4.0
- Context at failure: ~409,588 tokens (41% of 1M window)
- Session: ~197 user turns, ~201 assistant messages
Related Issues (Same Root Cause)
- #42256 — Read tool re-sends oversized images on EVERY subsequent message (OPEN)
- #37418 — MCP screenshot makes session permanently unusable (OPEN)
- #34751 — 99KB PNG triggers 20MB error; confirmed regression (OPEN)
- #30542 — Best root-cause writeup; accumulated image data permanently kills conversations (CLOSED by stale bot, NOT fixed)
- #38496 — Confirmed regression from v2.1.80 to v2.1.81 (CLOSED as duplicate)
Suggested Fixes
- Stop persisting base64 blobs in full — prune inline image data from conversation history after initial processing, or use a content reference/cache
- Add a pre-flight size check — before dispatching the API request, check serialized size and auto-compact or strip images if approaching 20MB
- Fix the error message — "conversation payload too large" not "try with a smaller file"
- Exempt \
/feedback\— truncate context before sending feedback so the reporting mechanism always works - Show a warning at 80% of the cap — let users \
/compact\proactively before hitting the hard wall - Differentiate file path (\
Read\tool) vs URL behavior — both should be handled consistently
Showing cached comments. Read the full discussion on GitHub ↗
15 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
Update — Comprehensive Root Cause Analysis Added
This issue has been significantly updated since initial filing with forensic evidence from two independent sessions (Claude Code + Codex CLI audit):
Key findings:
Readtool (corrected from earlier version)/rewind, the base64 persists — text-only prompts still carry the full accumulated payloadReadtool) and file URLs behave differently initially, but both eventually failThis is NOT a duplicate of the issues flagged by the bot (#34751, #42084, #26019). While related, this issue provides:
Readtool is NOT the initial cause (correcting the narrative in #42256 and #30542)/feedbackitself is blocked by this error (UX loop)The related issues were either closed by the stale bot without a fix, or lack this level of forensic detail.
cc @anthropics — requesting review of the updated root cause analysis and regression evidence above.
Update — Issue Body Revised Based on Independent Forensic Review
The issue body has been significantly revised based on two independent code reviews by Codex CLI (GPT-5), which audited both the affected session JSONL and this follow-up session's work.
Changes made:
Readtool. Forensic analysis proves the firstRequest too largeerror (JSONL line 356) occurred before the firstReadtool call (line 390). Inline pasted/attached images are the initial trigger./feedbackclaim softened — Changed to "not a reliable escape hatch" rather than claiming it definitively fails with the same errorMethodology
The affected session JSONL was analyzed by an independent Codex CLI session which:
cc @anthropics — Title was updated from the original "Request too large (max 20MB) error on plain-text conversations with no images" to more accurately reflect the root cause identified through forensic JSONL analysis. The issue is not limited to text-only messages — it affects all messages once accumulated inline image base64 in session history exceeds the 20MB API request cap. The full issue body and prior comment document the forensic methodology and evidence.
Release Notes Analysis
Prior image-related fixes in Claude Code:
| Version | Release Date | Change |
|---------|-------------|--------|
| v1.0.28 | Pre-2026 | "Resizes images before upload to prevent API size limit errors" |
| v2.1.37 | Feb 7, 2026 | "Stripping images before sending to the compaction API" (#26188) |
| v2.1.43 | ~Feb 2026 | "Fixed image dimension limit errors to suggest /compact" |
| v2.1.71 | Mar 7, 2026 | "Fixed the Read tool putting oversized images into context when image processing failed" |
| v2.1.72 | Mar 10, 2026 | "Fixed oversized and truncated images from Bash data-URL output" |
The v2.1.71/v2.1.72 fixes addressed specific edge cases (Read tool failure path + Bash data-URL output) but did not implement a general pre-flight payload size check or image pruning from accumulated conversation history.
This bug was reproduced on v2.1.91 (released Apr 2, 2026). The v2.1.91 changelog contains no image-related changes. We cannot determine from public changelogs alone whether a regression was introduced between v2.1.72 and v2.1.91, or whether the partial fixes simply never covered the accumulation scenario.
The per-image resize from v1.0.28 reduces individual image sizes, but the cumulative sum of 14+ resized Retina screenshots still exceeds 20MB when persisted in conversation history.
The
image-stripstrategy in Cozempic v1.6.11 directly addresses this — removes accumulated base64 image blocks, keeps only the most recent 20%. Prevents the "Request too large" error by keeping JSONL under the 20MB API limit.pip install cozempic && cozempic initUnfortunately, I've had cozempic and was hoping this was going to solve this issue. It even might have helped for the period where I didn't seem to have this issue re-appear, but it's definitely back in full force... 😕
💡 Session Recovery Workaround (No ffmpeg needed)
If your session is bricked by an oversized image, here's a clean recovery method that preserves your full context:
~/.claude/projects/(orC:\Users\<You>\.claude\projects\on Windows).jsonlfile (by modified date)/initto re-initialize project context.jsonlfile into the chat and tell Claude: "Analyze this session log and get fully caught up on where we left off."This works because the
.jsonlfiles contain the complete conversation history. Feeding it into a fresh session gives you all the context without the corrupted state (the stuck oversized image causing the 400 error loop).Adding one UX-specific angle from a Windows / Claude Code workflow.
The current issue already captures the root cause well: accumulated inline image/base64 history can make later text-only turns fail with
Request too large, even when token context usage still looks safe.The missing piece from a user perspective is that Claude Code exposes token context but not serialized request body size. For image-heavy UI/frontend workflows, those budgets diverge sharply.
Concrete UX requests:
Request body: 24.5 MB / 32 MB./compactLonger context models do not solve this because the failure is serialized request-body bytes, not only token context. The UI currently makes this hard to predict because the visible context meter can look healthy while the request body is already near the hard limit.
My duplicate issue #56691 was auto-flagged against this issue, so I am adding the more specific UX requests here instead.
Filed a related proposal at #56691 focused on the UX side: showing request body byte usage in real time and preflighting pasted/uploaded images before they hit the 32MB ceiling (complements the root-cause findings in this thread).
This is a painful one — accumulated base64 images silently bloating the request until everything breaks. I built Cozempic (https://github.com/Ruya-AI/cozempic) partly to address this. Its
image-stripstrategy removes inline base64 image blocks from session history, and the guard daemon can auto-prune before you hit the 20MB wall.pipx install cozempic && cozempic treat --rx standardon the affected session should clear the accumulated images. Would be curious if it helps your case.Inline image base64 accumulating in session history is a known context killer — each screenshot stays in the JSONL forever and gets re-sent every turn. Cozempic has an
image-stripstrategy that specifically targets this: it removes base64 image data from older messages while preserving the text context around them. The guard daemon can do this automatically before you hit the 20MB wall.pip install cozempic && cozempic treat --rx standardto clean up an existing session, orcozempic guardto prevent accumulation. Would be interested to know if it resolves the blocking for you.Been dealing with this exact problem — inline screenshots accumulate as base64 in the JSONL and eventually hit the 20MB wall. I built Cozempic which has an
image-stripstrategy that specifically targets base64 image blocks in session history, removing them before they snowball. The guard daemon can also auto-prune proactively so you never reach the limit.pip install cozempic && cozempic treatto clean an existing session, orcozempic guardfor continuous monitoring. Would be curious if it helps with your workflow — happy to hear feedback.Cross-reference: this byte-payload-accumulation class also manifests in primarily-text sessions where tool output (long Bash stdout, repeated curl/API responses, persisted grep dumps) drives the payload past the 20-32MB ceiling — same wire-size-vs-token-count root cause class as the image accumulation here, just via a different content vector.
Recent data point on v2.x: hit
payload est ~24 MB / 32 MBat only 26% token usage (257.9k/1M, Opus 4.7) with one small image paste total. Tool output accumulation dominated.The v2.1.71/v2.1.72 fixes addressed image-specific paths. A general payload-size accounting layer (as proposed in #56691) would catch both classes — image accumulation and tool-output accumulation — with one mechanism. Bumping #56691 with similar framing.
This class needs payload-byte accounting, not only token accounting.
Persist images as content refs with hash, byte size, MIME type, producer turn/tool id, and replay policy, then decide per request whether to inline, downsample, omit, or ask for confirmation. Preflight should include both current request bytes and projected next-turn replay bytes.
Regression: paste enough images to exceed the body budget later, send a text-only follow-up, and assert the client refs or prunes before the API rejects it.
---
_Generated with ax._