[BUG] Auto-compact preTokens values vary across sessions on the same model/context

Status Open
Reported on v2.1.226
Maintainer reply None cached
Activity 0 comments · opened Aug 14, 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?

"trigger":"auto" compact_boundary events, taken from raw session transcript logs (~/.claude/projects/<url-encoded-cwd>/<session-id>.jsonl), show different preTokens values across sessions on the same model, context size, autoCompactWindow, and CLAUDE_AUTOCOMPACT_PCT_OVERRIDE configuration:

  • 200k-context Opus 5 session: three automatic triggers at preTokens 151,935 / 145,504 / 146,586.
  • 1M-context Opus 5 session: four automatic triggers at preTokens 148,146 / 147,584 / 149,617 / 148,226.
  • 1M-context Sonnet 5 session (session A): two automatic triggers at preTokens 148,781 / 148,631.
  • 1M-context Sonnet 5 session (session B, different project, same machine): zero automatic triggers up to preTokens 294,554, at which point the user manually compacted. (This session's environment was later found to have DISABLE_AUTO_COMPACT=1 set; see Section 13.)
  • 1M-context Sonnet 5 session (session C, different project, same machine): three automatic triggers at preTokens 97,547 / 96,523 / 97,104, followed later in the same session by two manual compactions at preTokens 147,615 / 149,595 with no further automatic triggers in between.

What Should Happen?

Auto-compact should trigger based on the model's actual context window and the configured autoCompactWindow/CLAUDE_AUTOCOMPACT_PCT_OVERRIDE settings.

Error Messages/Logs

No explicit error message or crash. This is a silent behavioral issue, observable only in the session transcript logs Claude Code writes to ~/.claude/projects/<url-encoded-cwd>/<session-id>.jsonl.

200k Opus 5 session:

grep -o '"subtype":"compact_boundary".\{300\}' ~/.claude/projects/<project>/<session-id>.jsonl

Output (5 compaction events total in this session; automatic ones bolded):

**{"trigger":"auto","preTokens":151935,"postTokens":30528,"cumulativeDroppedTokens":8815706,"durationMs":199951,...}**
{"trigger":"manual","preTokens":123704,"postTokens":21481,"cumulativeDroppedTokens":8917929,"durationMs":116200,...}
**{"trigger":"auto","preTokens":145504,"postTokens":22989,"cumulativeDroppedTokens":9040444,"durationMs":123975,...}**
**{"trigger":"auto","preTokens":146586,"postTokens":17865,"cumulativeDroppedTokens":9169165,"durationMs":46662,...}**
{"trigger":"manual","preTokens":134746,"postTokens":17155,"cumulativeDroppedTokens":9286756,"durationMs":14074,...}

1M-context Sonnet 5 session A (two automatic triggers, back to back):

jq -c 'select(.subtype == "compact_boundary") | {trigger: .compactMetadata.trigger, preTokens: .compactMetadata.preTokens, postTokens: .compactMetadata.postTokens, timestamp}' ~/.claude/projects/<project>/<session-id>.jsonl
{"trigger":"auto","preTokens":148781,"postTokens":11354,"timestamp":"2026-08-14T21:28:08.784Z"}
{"trigger":"auto","preTokens":148631,"postTokens":11298,"timestamp":"2026-08-14T21:42:53.129Z"}

1M-context Opus 5 session (four automatic triggers logged over the session's life):

grep -o '"subtype":"compact_boundary".\{300\}' ~/.claude/projects/<project>/<session-id>.jsonl

Output (6 compaction events total in this session; automatic ones bolded):

{"trigger":"manual","preTokens":113571,"postTokens":8735,...}
{"trigger":"manual","preTokens":78610,"postTokens":16785,...}
**{"trigger":"auto","preTokens":148146,"postTokens":14372,...}**
**{"trigger":"auto","preTokens":147584,"postTokens":15005,...}**
**{"trigger":"auto","preTokens":149617,"postTokens":16611,...}**
**{"trigger":"auto","preTokens":148226,"postTokens":14030,...}**

1M-context Sonnet 5 session B (never auto-triggered, both compactions manual):

python3 -c "
import json
with open('<session-file>.jsonl') as f:
    for line in f:
        obj = json.loads(line)
        if obj.get('subtype') == 'compact_boundary':
            m = obj['compactMetadata']
            print(m['trigger'], m['preTokens'], obj['timestamp'])
"
manual 294554 2026-08-14T20:59:05.317Z
manual 185023 2026-08-14T22:41:52.704Z

1M-context Sonnet 5 session C (three automatic triggers clustered far below the ~148k band):

python3 -c "
import json
with open('<session-file>.jsonl') as f:
    for line in f:
        obj = json.loads(line)
        if obj.get('subtype') == 'compact_boundary':
            m = obj['compactMetadata']
            print(m['trigger'], m['preTokens'], obj['timestamp'])
"
auto 97547 2026-08-12T16:06:50.168Z
auto 96523 2026-08-12T16:07:32.183Z
auto 97104 2026-08-12T16:08:53.372Z
manual 147615 2026-08-12T18:41:37.012Z
manual 149595 2026-08-12T19:11:28.240Z

Steps to Reproduce

  1. Start a Claude Code session on Opus 5 (200k or 1M context) or Sonnet 5 (1M context, its only size).
  2. Work through a long agentic session past 100k tokens.
  3. Inspect the .jsonl transcript for compact_boundary events: grep -o '"subtype":"compact_boundary".\{300\}' <session-file>.jsonl.
  4. Compare preTokens on "trigger":"auto" events across multiple sessions on the same model/config.

Claude Model

Not sure / Multiple models

Is this a regression?

Yes, this worked in a previous version

Last Working Version

2.1.226

Claude Code Version

2.1.232 (Claude Code)

Platform

Google Vertex AI

Operating System

Windows

Terminal/Shell

WSL (Windows Subsystem for Linux)

Additional Information

  • Relevant config: autoCompactWindow is set in ~/.claude/settings.json (180000), NOT via an env var; the settings.json env block itself is empty, so all env vars below come from the shell, not from Claude Code's own config:

``json
// ~/.claude/settings.json (relevant keys)
"autoCompactWindow": 180000,
"env": {}
`
`
# shell env (CLAUDE_/ANTHROPIC_ vars only)
CLAUDE_CODE_USE_VERTEX=1
ANTHROPIC_VERTEX_PROJECT_ID=<redacted>
CLOUD_ML_REGION=global
CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=98 # also tested at 90, same result
ANTHROPIC_DEFAULT_SONNET_MODEL=claude-sonnet-5
ANTHROPIC_DEFAULT_OPUS_MODEL=claude-opus-5[1m]
ANTHROPIC_DEFAULT_HAIKU_MODEL=claude-haiku-4-5@20251001
``

  • Correction note: this issue originally reported the preTokens values for the 200k Opus 5, 1M Opus 5, and 1M Sonnet 5 (session A) triggers only, described as a fixed ~145-152k threshold. Two additional sessions on the same machine (session B: no automatic trigger up to 294,554; session C: automatic triggers at ~97k) are now included above.
  • Session B environment finding: running env inside session B's live Claude Code session shows DISABLE_AUTO_COMPACT=1 set. The installed Claude Code binary (2.1.232) contains the following auto-compact gating logic (extracted via strings on the binary):

``js
function dI(){if(Y.DISABLE_COMPACT)return!1;if(Y.DISABLE_AUTO_COMPACT)return!1;return Bd("autoCompactEnabled",!0).value}
`
DISABLE_AUTO_COMPACT being set makes this function return false unconditionally, independent of autoCompactWindow/CLAUDE_AUTOCOMPACT_PCT_OVERRIDE. This is separate from the preTokens variance reported above for sessions that did produce trigger:"auto"` events (200k Opus 5, 1M Opus 5, session A, session C).

View original on GitHub ↗