[BUG] CLI 2.1.145 sends literal "claude-opus-4-7[1m]" as model name on session resume, hits 404, silently falls back to 200K

Status Fixed / completed
Reported on v2.1.145
Maintainer reply None cached
Activity 7 comments · opened May 20, 2026 · closed Aug 19, 2026

Summary

Selecting "Opus 4.7 (1M context)" in the /model selector causes Claude Code CLI v2.1.145 to send claude-opus-4-7[1m] verbatim as the model name in the API request body on session resume. Anthropic API returns HTTP 404 (not_found_error: model: claude-opus-4-7[1m]). The CLI then silently falls back to bare claude-opus-4-7 (200K) for all subsequent traffic in the resumed session.

Environment

  • OS: macOS 25.4.0 (Darwin), arm64
  • Claude Code CLI: v2.1.145 (claude --version confirms)
  • Plan: Max
  • Reproduces: every claude --resume of a session that was originally created with 1M-context selection (or claude --continue). Also reproduces on /compact-triggered SessionStart hook execution path.
  • No suppressing env vars set:
  • CLAUDE_CODE_DISABLE_1M_CONTEXT — unset
  • CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC — unset
  • ANTHROPIC_MODEL — unset
  • ~/.claude/settings.json has no model field set (selection persists elsewhere in CLI internal state).

Evidence (intercepted via local HTTP proxy at ANTHROPIC_BASE_URL=http://127.0.0.1:8787)

Request body

{
  "model": "claude-opus-4-7[1m]",
  "messages": [/* 1 message, ~9 tokens (probe request) */]
}

Request headers

anthropic-beta: claude-code-20250219,oauth-2025-04-20,context-1m-2025-08-07,interleaved-thinking-2025-05-14,redact-thinking-2026-02-12,context-management-2025-06-27,prompt-caching-scope-2026-01-05
anthropic-version: 2023-06-01
user-agent: claude-cli/2.1.145 (external, cli)
x-stainless-arch: arm64
x-stainless-os: MacOS
x-stainless-package-version: 0.94.0
x-stainless-runtime: node
x-stainless-runtime-version: v24.3.0

Note: context-1m-2025-08-07 beta header IS correctly included.

Response (HTTP 404)

{
  "type": "error",
  "error": {
    "type": "not_found_error",
    "message": "model: claude-opus-4-7[1m]"
  },
  "request_id": "req_011CbE6iCwMt41bR967dEEQG"
}

Confirmation: silent fallback to 200K

Across the same 24-hour window on this machine:

  • 9 requests sent claude-opus-4-7[1m] → all returned 404
  • 5697 requests subsequently sent bare claude-opus-4-7 → all succeeded

Each session resume produces exactly one 404 probe followed by ~hundreds of bare-name requests. The probe failure is invisible to the user — no error surfaces in the CLI; subsequent requests just use the 200K variant.

Steps to reproduce

  1. Run /model and select "Opus 4.7 (1M context)" in a Claude Code CLI v2.1.145 session.
  2. Exit the session.
  3. Resume with claude --resume <session-id> (or just claude --resume and pick the session from the menu). Same behavior occurs when /compact triggers SessionStart hooks.
  4. Inspect outgoing HTTP traffic to api.anthropic.com (or use a local intercepting proxy).
  5. Observe first probe request body contains "model": "claude-opus-4-7[1m]" and receives 404.
  6. Run /context — denominator is /200k, not /1m.

Root cause hypothesis

The [1m] suffix appears to be a Claude Code internal alias for the 1M-context variant. The CLI should strip the suffix before serializing the model field into the API request body, and rely on the context-1m-2025-08-07 beta header (which IS being sent correctly) to enable the 1M window on the bare claude-opus-4-7 model.

v2.1.145 appears to be sending the bracketed alias literally — Anthropic API does not recognize claude-opus-4-7[1m] as a valid model name.

Tested workaround that did NOT work

Tried the workaround from <https://github.com/anthropics/claude-code/issues/34143#issuecomment-4241018253>:

{
  "model": "claude-opus-4-7[1m]"
}

placed in ~/.claude/settings.json. After restart, behavior unchanged — /context still shows /200k and proxy logs confirm the same 404-then-fallback pattern. Possible I entered it incorrectly; happy to retry if there's a known-good schema.

Related issues

  • #55504 ("Opus 4.7 ([1m] variant) capped at 200K context in Claude Code Desktop on Max plan") — potentially the same root cause from the Desktop surface. That report is currently flagged for auto-close as duplicate but no underlying issue has been closed/fixed; the API-level evidence in this report may help identify the actual mechanism.
  • #50803 (--model flag silently drops [1m] suffix) — related, different code path. That report attributes the bug to launcher flag handling; this report shows the same [1m] corruption occurs through /model + --resume with no flag involvement.
  • #53031 (silent direction swap to [1m] on 200K selection, v2.1.119) — opposite direction symptom, may share underlying alias-handling code.

What's unique in this report vs the existing ones

  1. Raw API evidence — 404 status code, exact error message body, and request payload. Existing reports speculate about cause based on /context output; this one shows the API rejection directly.
  2. Specific version — v2.1.145 (latest as of filing).
  3. macOS CLI — existing reports are Windows or Desktop.
  4. Resume-specific triggerclaude --resume and /compact SessionStart hooks both reproduce. Fresh sessions may not exhibit it (haven't tested fresh-session path exhaustively).
  5. anthropic-beta header is correct — rules out beta-header malformation as cause; the bug is specifically in the model field serialization.

Happy to provide additional proxy captures, full request/response dumps, or test specific candidate fixes if helpful.

View original on GitHub ↗

6 Comments

github-actions[bot] · 3 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/60548
  2. https://github.com/anthropics/claude-code/issues/50803
  3. https://github.com/anthropics/claude-code/issues/55504

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

eggrollofchaos · 3 months ago

Additional observations from continued testing on v2.1.145, macOS:

/model menu shows a synthesized 5th entry in the bugged state

In a session that has fallen into the 200K-fallback state, running /model shows 5 entries instead of the expected 4. Item 5 is a synthesized entry exposing the raw model ID (no [1m] suffix) and is marked current.

Bugged state (/model after resume):

Select model
  Switch between Claude models. Applies to this session only. For other/previous model names, specify with --model.

    1. Default (recommended)  Opus 4.7 with 1M context · Most capable for complex work
    2. Sonnet                 Sonnet 4.6 · Best for everyday tasks
    3. Sonnet (1M context)    Sonnet 4.6 with 1M context · Draws from usage credits · $3/$15 per Mtok
    4. Haiku                  Haiku 4.5 · Fastest for quick answers
  ❯ 5. Opus 4.7 ✔             claude-opus-4-7

Expected state (/model on a healthy session):

Select model
  Switch between Claude models. Applies to this session only. For other/previous model names, specify with --model.

  ❯ 1. Default (recommended) ✔  Opus 4.7 with 1M context · Most capable for complex work
    2. Sonnet                   Sonnet 4.6 · Best for everyday tasks
    3. Sonnet (1M context)      Sonnet 4.6 with 1M context · Draws from usage credits · $3/$15 per Mtok
    4. Haiku                    Haiku 4.5 · Fastest for quick answers

Strong evidence the CLI is holding split internal state: the "Default" entry implicitly maps to claude-opus-4-7[1m], but on resume the live resolution silently falls to bare claude-opus-4-7 (200K) and the UI surfaces that as a synthesized 5th entry. The user's original selection is no longer represented as "Default" because the bracketed-alias path is broken.

--model CLI flag workarounds that do NOT work

Tested at launch on v2.1.145:

claude --resume --model opus               # → 200K, same buggy state
claude --resume --model claude-opus-4.7    # → 200K
claude --resume --model claude-opus-4-7    # → 200K

None of these route the session to the 1M variant.

--model claude-opus-4-7[1m] in bash — partial success, "limbo" state

In bash (zsh requires quoting — see footnote), the bracketed-alias flag form passes through to the CLI:

claude --resume --model claude-opus-4-7[1m]
claude --resume --model claude-opus-4.7[1m]

Both launch successfully and /context reports /1m — so the 1M context window IS active. But the session is in a degraded "limbo" state:

  • Lower-right of the TUI displays: "⚠ Claude Opus 4 has been updated to the latest Opus."
  • "Auto mode unavailable for this model" surfaces.
  • /model shows the same 5-entry menu with the synthesized claude-opus-4-7 entry selected as current (not "Default").

Proxy capture during this state shows what's happening underneath. When --model claude-opus-4.7[1m] (dot form) is used, the CLI strips the [1m] suffix but keeps the dot form and sends claude-opus-4.7 (dot, no suffix) in the request body. Anthropic API returns:

404 not_found_error: model: claude-opus-4.7 was not found. Did you mean claude-opus-4-7?

After this wave of 404s, the CLI falls back again to bare claude-opus-4-7 (dash, no suffix). The 1M context window stays active because the context-1m-2025-08-07 beta header is still being sent — the API appears to honor 1M on the base claude-opus-4-7 model purely from the beta header. So the user gets 1M context "by accident" while the CLI thinks it's running a different (broken) model, hence the UI warnings and auto-mode unavailability.

The one workaround that fully works

In an already-launched REPL on a bugged session:

/model
→ select option 1 "Default (recommended)"

After selection, /context reports /1m, the menu collapses back to the expected 4 entries, auto-mode becomes available, and no "Opus 4 updated" warning. The fix persists only for the current session — resuming again re-corrupts the state.

zsh globbing note (not a Claude Code bug)

$ claude --model claude-opus-4-7[1m]
zsh: no matches found: claude-opus-4-7[1m]

This is zsh's glob behavior ([1m] parsed as a character class matching 1 or m). Quoting fixes it:

claude --model 'claude-opus-4-7[1m]'

Mentioning only because it surfaced during testing and might confuse other repro attempts. Not relevant to the underlying bug — bash and quoted-zsh both reach the same "limbo" state described above.

Summary of failure modes observed

| Launch path | /context | UI state |
|---|---|---|
| claude --resume (from [1m]-selected session) | /200k | 5-entry menu, item 5 selected |
| --model opus, --model claude-opus-4-7, etc. | /200k | 5-entry menu |
| --model claude-opus-4-7[1m] (bash or quoted-zsh) | /1m | 5-entry menu with synthesized item 5; "Opus 4 updated" / "Newer version available" warning; auto-mode unavailable or shown as not-supported depending on shell |
| /model → "Default (recommended)" in REPL | /1m | clean 4-entry menu, auto-mode available |

The exact label and effort-support indicator on the synthesized 5th entry varies across launch paths (Opus 4, Opus 4.7, Opus 4.7 (1M context), with various "Newer version available" / "Effort not supported" annotations), and varies between bash and quoted-zsh invocations of the same command. The variation itself is evidence that the CLI's internal model resolver is in a poorly-defined state when any [1m] path is exercised — different code branches surface different stale catalog entries. Happy to capture exhaustive variations if useful.

The 1M context window is reachable via beta header alone on bare claude-opus-4-7. The CLI's only correct path to set up that header + clean UI state is the in-REPL /model → "Default" selection. Every other path corrupts the internal model state to some degree.

andrey-dubnik · 3 months ago

I can confirm this really annoying issue is still going with v2.1.150

eggrollofchaos · 3 months ago

Still present on v2.1.154, macOS, Max. The [1m] naming convention carried forward to Opus 4.8 — the 1M selection's internal model id is now claude-opus-4-8[1m] (same [1m] suffix as the 4.7 case here), so the same leak path applies. Another reporter above confirmed v2.1.150, so it's spanned at least 2.1.145 → 2.1.154.

One narrowing datapoint from testing today: the bug is not triggered by the headless/print path. Driving a resume through a local logging proxy (ANTHROPIC_BASE_URL=http://127.0.0.1:8788):

  • claude -p "…" --output-format json (create) → request body "model":"claude-opus-4-8"200
  • claude --resume <id> -p "…" --output-format json (resume) → request body "model":"claude-opus-4-8"200

So -p/headless resume sends the clean model name and succeeds. The 404 + 200K fallback reproduces on the interactive TUI resume / --continue / compact-SessionStart paths, not the print path — which points at the interactive resume code path rebuilding the model string from the persisted /model display label rather than the headless request builder.

Filed #63396 for a related but distinct class of post-context-op request-construction 400s (system role at messages[0]; modified signed thinking blocks) seen in the same session-continuity area on 2.1.154.

houleixx · 2 months ago

Great forensic work — the resume-time 404 probe + silent fallback pattern is exactly the kind of bug that's invisible without intercepting the wire.

A couple of observations on your evidence:

  1. The probe always carrying context-1m-2025-08-07 in anthropic-beta but model: claude-opus-4-7[1m] in the body strongly suggests two separate code paths are responsible for header and body. The header is set in a "request prep" layer that knows about the 1M feature flag, while the body model string is interpolated in a different layer that's losing the suffix cleanup. Probably a regression in how the model name is sanitized between the /model picker state and the API request body — your claude --resume and /compact SessionStart paths probably both share that one sanitization step.
  1. The "9 of 5706" ratio is interesting — if every resume emits exactly one 404 + hundreds of 200K requests, it's not a retry loop, it's a single one-shot probe. That means Claude Code is intentionally validating the model string at session start, but the validator accepts claude-opus-4-7[1m] as valid and the upstream API doesn't. The validator and the model registry disagree.
  1. Workaround: export ANTHROPIC_MODEL=claude-opus-4-7-1m or set model in ~/.claude/settings.json explicitly — both bypass the /model picker state and should avoid the [1m] suffix getting added. (You said ANTHROPIC_MODEL is unset, but worth trying the settings.json form.)

For anyone else reading this and wondering how to intercept like you did: I use ccglass for the same purpose (local proxy on the loopback). It's open source MIT and gives you a dashboard + log of every request body. Yours sounds like it does the same job — but if you want the prompt/tool_call content too (not just the model field), ccglass persists the full body to a queryable log.

Filed with high hopes this gets fixed — the silent fallback is the kind of thing users will blame on "the model got worse" when really it's 200K context all along.

eggrollofchaos · 1 month ago

Follow-up: found the mechanism, and reproduced fresh on the current release (Claude Code 2.1.201, Opus 4.8).

The proxy in my original capture (127.0.0.1:8787) is the Headroom proxy this environment routes through via ANTHROPIC_BASE_URL.

Docs explain why a raw [1m]-suffixed model string can reach the API unmodified behind a gateway (#setting-your-model):

The check runs only on the Anthropic API. On Amazon Bedrock, Google Cloud's Agent Platform, Microsoft Foundry, Claude Platform on AWS, and behind an LLM gateway or a custom ANTHROPIC_BASE_URL, your provider or gateway defines the model names, so Claude Code passes any string through without checking it.

So behind a proxy, Claude Code skips its usual model-name validation and passes the literal string through, assuming the gateway resolves aliases itself. Headroom is a wire-compression proxy, not an alias-resolving gateway — it just forwards bytes to the real Anthropic API. A literal claude-opus-4-8[1m] string reaching that API unmodified → 404 → silent fallback to 200K.

Confirmed both directions (interactive session, current release):

  • ANTHROPIC_BASE_URL pointed at Headroom: create-with-1M → close → resume → silently drops to 200k. Matches this report.
  • ANTHROPIC_BASE_URL unset: same flow keeps 1M correctly.

Also re-tested the headless --print/--resume/--session-id path directly (not the interactive TUI) on 2.1.201, still behind Headroom, for both Sonnet 5 and Opus 4.8 — neither reproduces; contextWindow stays 1000000 across an explicit create+resume in both cases. So this is specific to the interactive session/picker path, not the general resume mechanism, and not model-specific.

Related: #74562 — same class of bug (a Headroom-style proxy breaking [1m] handling), different symptom shape: sonnet[1m] there fails to apply the window at all rather than reverting on resume.

100% reproducible through the proxy, 0% without it — I'd lean toward keeping this open. Claude Code should either resolve [1m] aliases before handing off to a non-default base URL, or fail loudly instead of silently downgrading context.

Edit: this likely isn't Opus-specific either. The "passes any string through without checking it" behavior quoted above is model-agnostic — any [1m]-suffixed alias should hit the same literal-passthrough → 404 → silent-fallback path behind a non-translating proxy. #74562 already reports sonnet[1m]/fable[1m] failing to apply the window there too, just surfacing on first selection rather than specifically on resume — plausibly the same underlying bug, different trigger point, not independently confirmed via the exact resume-then-404 sequence for those two.

Showing cached comments. Read the full discussion on GitHub ↗