Auto-compact not triggering on resumed sessions with Opus 4.6 (1M context)
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?
Description
Auto-compact never triggered during an extended heavy-usage session on Opus 4.6 (1M context). The conversation was resumed from a prior session that ran out of context — the resume injected a large summary at the top of the conversation. After resuming, auto-compact never triggered again despite hours of intensive work.
Environment
Model: Opus 4.6 (1M context)
Platform: Windows 11
Claude Code version: latest
Expected Behavior
Auto-compact should trigger as context approaches the 1M window limit, compressing prior messages to reduce per-message token cost. The system prompt even states: "The system will automatically compress prior messages in your conversation as it approaches context limits."
Actual Behavior
After resuming a compacted session, auto-compact never triggered. The context grew unchecked, and every message sent the full conversation history (500K+ tokens) back to the API. Combined with 8 agent spawns (~580K tokens total in agent calls alone), the entire usage allocation was consumed in approximately 1 hour.
Impact
Full usage allocation consumed in ~1 hour of work
Normal heavy sessions last 4-8+ hours before hitting limits
The resumed session appears to have blocked the auto-compaction mechanism
Hypothesis
The session resume mechanism may interfere with auto-compact tracking. The compaction system may not correctly track context size or compaction thresholds when a conversation is continued from a prior compacted session via the summary injection pattern.
What Should Happen?
claude code resume should not block auto-compact
Error Messages/Logs
Steps to Reproduce
Start a conversation with heavy tool usage (MCP server development, multiple agent spawns, large file reads/writes)
Session runs out of context and compacts / provides a summary for continuation
Resume the session ("continue from where we left off")
Continue heavy work — building an MCP server with 121 tools, spawning 8+ research agents, dozens of build/deploy/test cycles
Auto-compact never triggers again after the resume
Entire usage allocation drains in ~1 hour due to massive per-message token cost
Claude Model
Opus
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
2.1.80 (Claude Code)
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
PowerShell
Additional Information
_No response_
13 Comments
Auto-compact may not trigger on resumed sessions because the compaction threshold calculation uses the original session's token count, not the resumed context size.
Run this periodically (~every 30 minutes or when you notice slowdown) on resumed sessions.
If this shows high usage (>80%) but auto-compact hasn't fired, run /compact manually.
Happened again today, 4/14/26 8:36am EST, while Claude Code was reporting context of 294,544 tokens (not anywhere close to 1M)
Claude Code version 2.1.204 (per Claude Code, this is the latest version as of this moment )
Current version: 2.1.104
Checking for updates to latest version...
Claude Code is up to date (2.1.104)
Happened again today
<img width="1355" height="182" alt="Image" src="https://github.com/user-attachments/assets/3d6f0ebf-6fd4-440d-b914-f3d012dd9462" />
Still broken in 2.1.112 (macOS, Apple M1, VS Code)
Updated to 2.1.112 (released ~30 min ago as of writing) — issue persists.
Environment:
Claude Code: 2.1.112
Platform: macOS, Apple M1 (MacBook)
Interface: VS Code extension (anthropic.claude-code)
What's broken:
Auto-compact does not trigger when context fills up
Manual /compact command also fails with "Prompt is too long" error — so there is no workaround at all
Parallel subagents hang indefinitely
Regression started: ~April 10, 2026 (was working fine before that)
Impact: Cannot run multi-step agentic workflows. Even single long sessions are unusable because manual compact is also broken.
Please prioritize — this makes Claude Code non-functional for any project with large context.
Not sure if fixed in 2.1.113, but auto-compact has happened twice since start of 04/18/26. Noting that both time it occurred Tokens was being reported at < 500K. However, prefer auto-compaction early or token count being incorrect than complete failure to do auto-compaction.
Failed to auto-compact today at 513851 tokens, version 2.1.113
<img width="1144" height="156" alt="Image" src="https://github.com/user-attachments/assets/96718329-1cc9-40d5-95a2-a1f98120ed9b" />
Upgraded to 2.1.114 04/20/26
Adding a data point that differs slightly from the resume-session hypothesis:
The issue also occurs in fresh (non-resumed) sessions. On Windows 10 / Claude Code 2.1.113 / Max (5x) plan, auto-compact consistently fails to fire during heavy development sessions regardless of whether the session was resumed. The session usage page (claude.ai/settings/usage) showed only ~15% of the session allocation consumed when the error occurred — so the failure is not simply "context too large."
Critical UX impact not yet captured in this thread: When the limit is hit and auto-compact has not fired, manual
/compactalso fails with the same error. On the Max plan, the only way out of this stuck state is:/compactwith extra usage activeThis means the bug has a direct financial cost: users are forced to spend money from their account balance simply to recover from a compaction failure. There is no free workaround.
This behavior is reproducible across multiple sessions on this machine. Auto-compact works correctly on Linux (same account) and macOS (different account) with identical Claude Code version and configuration.
See also: #51207
Same issue confirmed on Opus 4.7 (1M context):
compact_20260112configured withtrigger.type: "input_tokens",value: 400000anthropic-beta: compact-2026-01-12confirmed sentsubtype:compact_boundarycount in session JSONL)/compactworked correctly when invoked: preTokens=868123, postTokens=3628, durationMs=1532Mechanism:
usage.input_tokensreports the per-request fresh/uncached portion under prompt caching (typically 1-6 tokens per turn), so cumulative cached context can grow to ~870K while the trigger metric never crosses any reasonable threshold.Suggested fix: have the trigger evaluate
input_tokens + cache_read_input_tokens + cache_creation_input_tokens(cumulative cached context) rather than per-request freshinput_tokens.Note for others hitting this: client-side workarounds (UserPromptSubmit hooks, sub-agents) cannot trigger
/compactprogrammatically — only the user-typed slash command works. Manual/compactor/exit + restartis the canonical mitigation today.@zh4ngx Your diagnosis explains exactly what I've been seeing. The
usage.input_tokensvalue reports only the fresh/uncached portion (1–6 tokens per turn under prompt caching), so any client-side trigger built on top of it will silently undercount and never fire.While we wait for the fix you proposed (
input_tokens + cache_read_input_tokens + cache_creation_input_tokens), I've been running aUserPromptSubmithook that bypasses the API metric entirely and estimates context size from the transcript JSONL byte count instead. In long sessions (300K+ tokens) it has been noticeably more reliable than the built-in indicator, because the JSONL contains the full message history regardless of cache state.Two key details that took some calibration:
tool_useblocks, role metadata, timestamps — so the standard 4 bytes/token rule for English prose is wrong here. Important caveat: this session was conducted in Russian. Cyrillic characters take 2 bytes each in UTF-8 (vs 1 byte for ASCII/Latin) and tokenize differently from English. For English-dominated, code-heavy, or mixed-language sessions the right ratio will likely differ. Recalibrate against your own usage by dividing the JSONL byte size by the total token count shown in/contextafter a long session./compactcorrectly. After a compact, the JSONL keeps growing but the live API context only contains thecompact_summaryplus messages after it. Counting full file size gives a 3–4× false-high estimate. Solution: scan the JSONL for the lastisCompactSummary: truemarker and count bytes only from that offset to EOF.The hook injects a single-line indicator into the model's
additionalContextviahookSpecificOutput, with three thresholds:[OK](<75%),[HIGH](>75%),[CRITICAL](>89%). At[CRITICAL]it tells the model to suggest the user wraps up the session manually before auto-compact does so destructively.The 89% CRITICAL threshold is user-specific and needs calibration for each individual workflow. It is set so that there's enough headroom for a graceful session-close procedure to run before the hard limit is hit. My own session-close protocol (writing state, decisions, and follow-ups to local disk) typically consumes ~20K tokens, occasionally up to 40K when there is a large amount of information to persist — so 89% gives me a comfortable buffer. If your wrap-up procedure is heavier (say, 50K tokens), drop the threshold accordingly so there's room for it to run before auto-compact takes over. If you don't have a structured wrap-up at all, the threshold doesn't matter much and you can set it close to the auto-compact trigger.
A note on the
LIMIT_AUTO_COMPACT = 955_000constant in the script: I once observed the bottom-right indicator showing 955K at the moment auto-compact kicked in, while the real cumulative cached context at that point was ~964K. I set 955K as a conservative value with a small buffer; if longer observations confirm my JSONL-based estimate tracks closer to cumulative cached context, I'll raise it to 964K. So treat this constant as my own empirical anchor, not a documented Anthropic threshold.Bonus tip: I recommend disabling auto-compact entirely
After hitting this bug a few times I disabled auto-compact for good. In
~/.claude/settings.json:With auto-compact off, the hard wall sits at ~997K (the actual
Messagesbudget you see in/context, i.e. 1M minus ~3.3% from 1M reserved by Anthropic for system overhead). That's noticeably more usable budget per session than what's available when auto-compact triggers earlier.In this configuration I bump
THRESHOLD_REDto 960K (warning to wrap up) and try to hit/clearmanually around 985K rather than letting anything else clean up.Why prefer manual
/clearover auto-compact, even with a healthy threshold:/clearreload (300–500K of project memory files I deliberately load) gives the model far more relevant context than any auto-compact summary can. Compared to that, the 50K of auto-compact recap is noise.So the path I've settled on:
DISABLE_AUTO_COMPACT=true.[HIGH](75%) start finishing what I'm on; at[CRITICAL](~960K with this setup) trigger structured wrap-up; manually/cleararound 985K.This isn't going to fit everyone — if your workflow doesn't have a structured wrap-up phase, auto-compact at least gives you something rather than a hard crash. But for anyone investing in their own session-close protocol, disabling auto-compact and steering manually wins on both context quality and effective token budget.
Full hook script
Python, stdlib only:
Install via
~/.claude/settings.json(The
DISABLE_AUTO_COMPACTenv var is optional — see the bonus tip section above.)Caveats
.jsonlbyte size by the total token count shown by/contextafter a long session, and updateBYTES_PER_TOKEN.isCompactSummaryfield name in particular is what I use to detect compact boundaries — if Anthropic renames it, the post-compact handling silently breaks (the script just falls back to counting full file size).Hope this is useful as a stopgap until the official fix lands. Happy to iterate on the calibration if anyone runs it on different model/language mixes.
Also available as a gist: https://gist.github.com/tovamerika-ux/f1c539ea5baa255b6c090b36984aea51
@JeremyFriesen Yes, I just hit a related case worth adding here as another data point.
I ran a stress test in a fresh, empty session — Opus 4.7 1M, Medium effort, with
DISABLE_AUTO_COMPACT=trueset — and asked the model to read every file in the project non-stop. The session crashed withPrompt is too longwhile the GUI dashboard's Context window header still showed 761.2k / 1.0M (76%).But look at the breakdown the same dashboard shows side-by-side:
<img width="876" height="531" alt="Image" src="https://github.com/user-attachments/assets/a0ead313-9cce-488f-80a6-1dd70006c456" />
The header says 76% used, but the
Messagesline shows 99.7% (≈997K) andFree space = 0. Those two numbers describe the same session and they disagree by 236K. Adding the breakdown lines together gives 1,056K — already over the 1M model limit on paper.So to your point about the GUI being unreliable:
the same dashboard can both under-report (the header /
input_tokens-based metric) and accurately report (theMessagesline +Free space = 0) at the same moment, and the header is the one most people look at.I think this is a direct manifestation of @zh4ngx's diagnosis above. Under prompt caching, the dashboard's headline number tracks
usage.input_tokens(the fresh/uncached portion, 1–6 tokens per turn), so it crawls slowly and "looks fine" — while the real cumulative cached context, which is what the API actually checks against the model limit, is already at the wall. The breakdown'sMessages 99.7%andFree space 0lines tell the truth, but they're easy to miss next to the big "76%" at the top.In my case the failure mode is different from yours (you saw failures while the session-allocation page reported only 15% consumed; I saw the in-session header at 76% while the actual context was full), but the underlying problem looks identical: Claude Code's main visible token metric is decoupled from the metric the API uses to enforce the limit, and the gap is systematic, not random.
Would be useful if Anthropic could make the dashboard header use the same metric
zh4ngxproposed for the auto-compact trigger (input_tokens + cache_read_input_tokens + cache_creation_input_tokens). That would unify what the user sees with what the API enforces — and the reading-files stress test I ran would have surfaced as "97% used" instead of the misleading "76%".For the moment, I've found that the most reliable way to know how full a session really is, is to look at
/contextand watch theMessagespercentage andFree spaceline — not the headline number. Or, even simpler, run a hook that estimates context size directly from the transcript JSONL byte count, which sidesteps the API metric entirely (I posted one earlier in this thread).@tovamerika-ux — great hook, thanks for building this. Replying with the English/code recalibration data you asked for.
My primary session jsonl (Opus 4.7, long coding session, pre-compact): 30,376,135 bytes. Divide by
/contexttotal tokens for exact BPT — I will compute and post the ratio once I have the token count from a long session. Rough expectation: English/code should land around 3-4 bytes/token (compared to your 7.5 for Cyrillic Russian), since English/code UTF-8 is mostly 1-byte ASCII with occasional 2-4 byte sequences for emoji/special chars.For anyone calibrating their own: the simplest method is to paste
/contextinto a file, grab the total token count, thenwc -c <session.jsonl>and divide. No need to guess.Two minor additions based on our experimentation:
DISABLE_AUTO_COMPACT=trueis essential — the auto-compact trigger is irreparably decoupled from real context fullness. Manual/clearat ~985K gives you control over when compression happens.find_last_compact_offsetis a good idea, but note that/clear(manual compact) and auto-compact write different markers. Watching forisCompactSummary: truecovers both, which is correct.The root issue here is that once auto-compact stops tracking after a resume, nothing is bounding the JSONL, so you pay full freight (500K+ tokens) on every turn. Until the resume/compaction-tracking bug is fixed, you can put a hard ceiling on session size yourself with cozempic (
uvx cozempic, orpip install cozempic). It prunes the session JSONL directly — stale file reads, aged tool outputs, redundant metadata — which restores a big chunk of effective context, and its guard daemon re-prunes at configurable thresholds even when Claude Code's own auto-compact never fires. On heavy resumed sessions that's typically where the per-turn token cost is coming from. Repo: github.com/Ruya-AI/cozempic.Love the manual workarounds especially by @tovamerika-ux - but I must admit I don't remember hitting this until recently, though now that I read about the dead payload, it makes perfect sense to have a hand-off prompt and do a fresh session. Could anyone suggest a way to automatically generate a handoff prompt to be used as a preamble for a new session? It saves tokens and yet (in a meaningful way) does a better job than auto-compact anyway since the HITL gets to modify the information before blindly pasting in the hand-off .. some things aren't worth moving into a new conversation with, which has always been a problem with auto-compact (and no doubt with every LLM on the planet, this isn't just Claude's problem, it's a gotcha on how MLPs work at this stage in the game).
Closing for now — inactive for too long. Please open a new issue if this is still relevant.