opusplan downgrades plan mode to Sonnet past 200k — Claude Code regression (it previously auto-compacted at 200k and kept Opus)

Status Fixed / completed
Reported on v2.1.162
Maintainer reply None cached
Activity 6 comments · opened Jun 4, 2026 · closed Jun 11, 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?

With --model opusplan on long sessions, two connected regressions show up in recent Claude Code versions:

1. New plans are generated by Sonnet once context exceeds ~200k. In plan mode, as soon as the session passes ~200k tokens, plan-mode responses are produced by Sonnet instead of Opus. The status bar reflects it (e.g. Sonnet 4.6 · 204.2k/200k — over 100% of the shown 200k), but nothing signals this is an opusplan downgrade rather than a deliberate choice. On the earlier Claude Code version — the one whose opusplan used Opus 4.7 for plan mode — plan mode stayed on Opus and did not downgrade.

2. Plan execution now runs on Sonnet with up to ~1M context. On the latest Claude Code version, after exiting plan mode the plan is executed on Sonnet with context allowed to grow up to ~1M. In previous Claude Code versions, plan execution ran on Sonnet capped at ~200k.

What Should Happen?

Plan mode under opusplan must stay on Opus — keeping Opus for planning is the entire point of the preset, so the switch to Sonnet should not happen at all, and the planning model should never be silently swapped mid-session.

Two ways to fix it:

  • Restore the earlier Claude Code behavior: auto-compact at ~200k when running opusplan, so context never crosses the threshold and Opus is retained in plan mode.
  • Or add an explicit opusplan[1m] preset that embraces the 1M window — Opus[1m] in plan mode (no downgrade to Sonnet) and Sonnet[1m] for plan execution.

Error Messages/Logs

Steps to Reproduce

  1. claude --model opusplan on the current Claude Code version (opusplan uses Opus 4.8 for plan mode).
  2. Grow a plan-mode session past ~200k tokens.
  3. Plan-mode replies are now produced by Sonnet; status bar shows e.g. Sonnet 4.6 · 204.2k/200k.

(On the earlier Claude Code version — the one that used Opus 4.7 for plan mode — the same session auto-compacted at ~200k and stayed on Opus.)

Claude Model

Other

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

2.1.162

Platform

Other

Operating System

macOS

Terminal/Shell

iTerm2

Additional Information

Regression across Claude Code versions: on the earlier Claude Code version — the one whose opusplan used Opus 4.7 for plan mode — context was compacted at ~200k in both modes. Plan mode therefore stayed on Opus (it never crossed the threshold), and execution ran on Sonnet capped at ~200k. On the current Claude Code version (opusplan now uses Opus 4.8 for plan mode) this 200k compaction no longer fires — execution runs on Sonnet with the full ~1M window, and plan mode, once context exceeds 200k, downgrades from Opus to Sonnet.

Mechanism (reverse-engineered from the bundled CLI JS — symbol names paraphrased, treat as a lead rather than gospel): the plan-mode model selector keeps Opus only while an "exceeds 200k tokens" guard is false; that guard compares the most recent assistant turn against a hardcoded 200000 literal. Once usage is no longer compacted below 200k, the guard trips and plan mode falls back to Sonnet.

Why this is counterintuitive: choosing opusplan is an explicit request for Opus-quality planning, yet the longer/more complex the session — exactly when Opus matters most — the more certain the fallback to Sonnet. The status bar shows the active model, but nothing connects it to an opusplan policy downgrade, so it reads as expected behavior.

After the downgrade the session continues on Sonnet with the ~1M window, so context keeps accumulating toward ~800k.

Workaround that restores Opus planning (re-creates the earlier Claude Code behavior): set CLAUDE_CODE_AUTO_COMPACT_WINDOW=200000 so context is compacted before the 200k guard trips. Note CLAUDE_CODE_DISABLE_1M_CONTEXT=1 alone is not sufficient — only the auto-compact window actually caps usage below the threshold.

View original on GitHub ↗

6 Comments

github-actions[bot] · 2 months ago

Found 2 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/43005
  2. https://github.com/anthropics/claude-code/issues/54426

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

liqlvnvn · 2 months ago

Not a duplicate — same architectural class ("silent Opus→Sonnet downgrade"), distinct surface.

  • #43005 reports the same primary symptom (Plan mode Opus→Sonnet at 200k) but is already closed/locked as a duplicate of #40269, and #40269 is a different root cause — quota exhaustion → Haiku, not a 200k context-window threshold. So the plan-mode-200k downgrade has no live, correctly-scoped issue tracking it. This is that issue, and it's opusplan-specific. I used opusplan heavily before the Opus 4.8 release and plan mode reliably stayed on Opus; the silent downgrade started with 4.8 — the 200k auto-compact that previously kept the session under the threshold no longer does so by default, so the downgrade now triggers in ordinary use with no manual override. That regression isn't captured in #43005/#40269.
  • #54426 is about general /model opus[1m] max-effort sessions (not plan mode, not the opusplan preset) plus a separate /compact-non-execution bug. Different trigger, different threshold.

Novel here and not in any of the above: (1) opusplan plan-mode Opus→Sonnet specifically tied to the disappearance of the 200k auto-compact; (2) plan execution now runs on Sonnet with the full ~1M window instead of the previous ~200k cap; (3) reverse-engineered guard + working workaround (CLAUDE_CODE_AUTO_COMPACT_WINDOW=200000); (4) concrete fix proposals (restore auto-compact, or add an explicit opusplan[1m] preset). Keeping open as a distinct regression. 👎 to prevent auto-close.

liqlvnvn · 2 months ago

Confirmed fixed in v2.1.172 — thanks! 🙏

The fix landed in Claude Code v2.1.172. Both launch presets now behave exactly as requested here:

| Launch | Plan mode | Execution |
|---|---|---|
| claude --model opusplan | Opus 4.8 — 1M, auto-compacts at ~200k | Sonnet 4.6 — 200k |
| claude --model 'opusplan[1m]' | Opus 4.8 — 1M | Sonnet 4.6 — 1M |

So the two presets give a clean cost-vs-headroom choice: plain opusplan keeps Opus on a 1M window for planning while capping Sonnet execution at 200k, and opusplan[1m] puts both on 1M. Either way the >200000 guard that caused the Sonnet downgrade in plan mode is no longer tripped.

One small non-blocking follow-up: opusplan[1m] is launch-flag only — /model opusplan[1m] returns "not found", unlike /model opus[1m] / sonnet[1m]. Parity there would be nice, but it's not needed for this issue.

Closing as fixed. Thanks for the quick turnaround! 🙏

ANogin · 2 months ago

I am using Bedrock API and already have Sonnet 4.6 1M and Opus 4.8 1M as my default sonnet/opus models. Still, with opusplan, there is a SILENT switch to Sonnet at 200K when in planning mode. There IS now opusplan[1m] but it ONLY works via commandline --model, and does NOT work via /model or settings.json preset.

What's worse - even with --model 'opusplan[1m]', Claude Code 2.1.190 keeps dropping to Sonnet (not right away, perhaps? I am confused by what is going on and do not want to waste more time and tokens on debugging). With a 200k+ pre-existing session, claude -r [...] --model 'opusplan[1m]', I saw 'Opus 1M' in my statusline after Shift-tabbing to plan mode, but after continuing the session for a bit, I realized the statusline was showing sonnet again :(

dilippanicker · 1 month ago

Seeing this recur on v2.1.216 (newer than the v2.1.172 fix) with the plain opusplan preset — not opusplan[1m] — which per the fix table above is the one that's supposed to auto-compact at ~200k specifically so the guard never trips.

In a single ~7-hour session, EnterPlanMode was called 4 times. Model observed on the turns immediately following each call, cross-referenced against cache_read_input_tokens + cache_creation_input_tokens + input_tokens from the transcript at that point:

| # | Total context at call | Switched to Opus? |
|---|---|---|
| 1 | ~146,124 tokens | Yes |
| 2 | ~232,502 tokens | No — stayed on Sonnet |
| 3 | ~383,490 tokens | No — stayed on Sonnet |
| 4 | ~471,994 tokens | No — stayed on Sonnet |

The one success is the only call under 200k; all three failures are over it — matches the guard mechanism described above exactly.

The part that seems like a regression of the fix itself, not just the original bug: zero auto-compaction events occurred anywhere in this transcript, despite context growing unchecked from ~146k to ~472k tokens on the plain (non-[1m]) opusplan preset — which is exactly the case the v2.1.172 fix was supposed to handle by keeping the session compacted below the threshold. settings.json had no explicit autoCompactWindow override (default), autoCompactEnabled unset (defaults on).

So this doesn't look like the same shape as the original report (guard trips because compaction stopped happening by default) — it looks like auto-compact isn't firing at all for plain opusplan on this version, silently, with no error or warning either for the missed compaction or the resulting downgrade. Nothing in the product surfaced any of this — it was only caught by manually diffing the transcript's message.model field against wall-clock time after the fact.

Happy to share the raw transcript excerpts (token usage + model per turn) if useful for reproduction.

dilippanicker · 1 month ago

Follow-up to my last comment — dug further into the same transcript and found what I think is the actual mechanism, not just the symptom.

Re-checked all 4 EnterPlanMode calls from that session directly against the transcript's message.usage fields (independent of the earlier table, same numbers):

| # | Context at call | Switched to Opus? |
|---|---|---|
| 1 | ~127k | Yes |
| 2 | ~246k | No |
| 3 | ~386k | No |
| 4 | ~479k | No |

Zero exceptions — every call under ~200k switched, every call over it didn't.

The new part: I searched the entire transcript (not just up to the last plan-mode call) for any compaction event, and found exactly one, with a compactMetadata block:

timestamp: 2026-07-22T06:24:10 UTC
trigger: auto
preTokens: 1,104,133
postTokens: 212,282

That's ~10 hours after the last failed switch (20:33 UTC), and it didn't fire until context hit 1.1M tokens — nowhere near the ~200k ceiling the v2.1.172 fix table says plain opusplan should auto-compact at. For the entire multi-hour window covering all three failed switches, auto-compaction simply never engaged.

So this doesn't look like "auto-compact stopped happening" (my last comment's framing) — auto-compact does still run, just against something much closer to the full 1M context window than the ~200k specifically documented for plain opusplan. Once context first crosses ~200k, the plan-mode guard trips and then has no way to get relieved until a compaction that arrives 5x too late to matter for that session's plan-mode usage.

If it's useful, I have the raw transcript lines around the compaction event (compactMetadata + isCompactSummary) and can paste the full block rather than just the summary numbers above.