[BUG] Oversized plan file makes a session unrecoverable: compaction yields postTokens > preTokens, and resume replays the stale copy

Status Open
Reported on v2.1.281
Maintainer reply None cached
Activity 0 comments · opened Sep 24, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Summary

A plan file that grew to ~2.5 MB (base64-embedded images) is re-attached in full on every turn while in plan mode. That pushed the context from ~512k to ~1.14M tokens and triggered auto-compaction. Because the plan file is re-attached after compaction, the compacted context was larger than before (preTokens: 1142389, postTokens: 1270827), so every following message failed with Prompt is too long. Fixing the plan file on disk did not help, because resume replays the copy stored in the transcript. The only way to recover was to edit the session JSONL by hand.

Evidence (from the session JSONL)
  • Last assistant turn before the plan was submitted: total input about 512,536 tokens.
  • ExitPlanMode tool_use line: 2,517,651 bytes (the base64 plan).
  • compact_boundary entry: "trigger":"auto","preTokens":1142389,"postTokens":1270827
  • First entry after the boundary: an attachment of type plan_file_reference, 5,032,739 bytes. It holds the full plan twice, once in attachment.planContent (2,515,833 chars) and once in rendered[0].content (2,516,064 chars).
  • /context then reported 2.4M / 1.0M tokens (241%), with Messages at 2.4M.
  • After resume: the same stored plan_file_reference entry is replayed, and the result is again Prompt is too long.

What Should Happen?

Expected behavior
  1. Compaction should never produce a context larger than its input. If content that is re-attached after compaction (plan file, memory, etc.) alone exceeds the budget, it should be truncated or summarized, or the user should get an actionable error such as "plan file X is N tokens; shrink it".
  2. Plan file attachments should have a size cap. Past a threshold, attach the path and a head/tail excerpt instead of the full content, and warn.
  3. On resume, the plan attachment should be rebuilt from the current file on disk, or at least the user should have a way to refresh it. Otherwise fixing the file cannot rescue the session.
  4. Nice to have: a way to resume from before the last compaction when the raw history is still in the transcript. In this case the pre-compaction history fit in ~515k tokens once the base64 was removed. Compaction was forced by one bad attachment, not by the conversation itself.

Error Messages/Logs

Prompt is too long, "trigger":"auto","preTokens":1142389,"postTokens":1270827

Steps to Reproduce

  1. Start a session and work until context usage is about 50% (~500k tokens).
  2. Enter plan mode. Write a plan file that embeds several PNG images as data:image/png;base64,... (5 images, ~2.5M characters in total). In my case the assistant did this itself so the images would render in the plan review UI, because local image paths do not render there.
  3. Call ExitPlanMode and stay in plan mode (leave review comments).
  4. The next turn triggers auto-compaction, then Prompt is too long. Every later message, including background task notifications, fails the same way.
  5. Shrink the plan file on disk (replace the base64 images with paths), then resume the session. It still fails with Prompt is too long.

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.281 (Claude Code VS Code extension; standalone CLI is 2.1.185)

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

VS Code integrated terminal

Additional Information

  • Environment: VS Code extension via WSL2 remote (Ubuntu 20.04, kernel 6.18.33.2-microsoft-standard-WSL2), Opus with 1M context.
Related issues
  • #92434, #85489: re-injected instruction files overflow the window after compaction. Same mechanism, but those are about CLAUDE.md/rules; this one is the plan file, which has no size cap and is attached in full every turn.
  • #85483: compaction increases context. Same symptom, different cause (the rebuild floor).
  • #92949: an attachment is re-injected from a snapshot instead of the on-disk file. Same class of problem; here it happens on resume, and the plan attachment is stored twice.
Workaround I used
  1. Backed up the transcript. In the post-boundary plan_file_reference entry, replaced both attachment.planContent and rendered[0].content with the shrunk plan. After this, the original session loaded again, but only from the compaction summary.
  2. To get the full history back, copied the pre-boundary lines into a new JSONL with a new sessionId, and removed the base64 from the ExitPlanMode input. The parentUuid chain was intact back to the first message. Resuming it worked at ~51% context.

Both steps depend on undocumented transcript internals. This is related to the issues above, but the plan-file path and the stale copy replayed on resume are not covered by any of them.

View original on GitHub ↗