[BUG] Subscription features are withdrawn when `ANTHROPIC_BASE_URL` isn't the official string, even when the proxy terminates at Anthropic

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

Claude Code decides "this is a third-party provider" by comparing ANTHROPIC_BASE_URL against
the official endpoint, and then withdraws subscription features one at a time — while the traffic
still terminates at api.anthropic.com, still carries a genuine subscription credential, and the
account is still entitled to every one of those features.

Three symptoms of that one inference are known, and only two have been reported:

| Feature withdrawn | Status |
| --- | --- |
| 5-hour / 7-day usage meters (rate_limits is null) | unreported — this issue |
| 1M context window (drops to 200k) | #68522 — resolved for unrecognised gateway ids |
| Remote Control ("only available when using Claude via api.anthropic.com") | #72749 — open, marked stale |

The concrete, reproducible defect below is the usage meters, because it carries evidence the other
two can't: the client receives the numbers and discards them. Responses carry
anthropic-ratelimit-unified-* headers on every call, an ordinary reverse proxy passes them
through untouched, and I logged them arriving on the very requests whose usage was then not
displayed. Nothing needs to be looked up, granted, or inferred — the data is in hand.

This is not "before the first API call" (#76036): it persists after successful /v1/messages
round-trips whose own responses carried the utilization headers.

The trigger is the base URL's value, not the presence of a proxy. Setting
ANTHROPIC_BASE_URL=https://api.anthropic.com explicitly keeps the meters working, and reaching
the same proxy by DNS redirection while leaving the variable unset also keeps them working — the
proxy is identical in both, only the string differs. So a deployment that merely proxies — a
corporate egress proxy, an audit gateway, a token-compression proxy (#72749), or a sandboxing tool
that keeps the credential off the machine running the agent — is treated as though it were a
third-party provider that cannot report subscription usage.

The narrow fix is to render the meters from the headers received. The fix that would also close
\#68522's remaining edge and #72749 is at the inference: what is proxied is not the same question
as who is answering, and only the second one determines what the account is entitled to.

What Should Happen?

The meters should render from the headers actually received, and be absent only when no such
headers arrived. That rule is correct under every deployment: Bedrock, Vertex, Foundry and
third-party gateways don't send these headers, so they would show nothing exactly as they do
today, while a proxy terminating at Anthropic would show the real numbers. Keying the display off
the configured URL rather than off the received response is what produces the wrong answer here.

Error Messages/Logs

No error is produced — that is part of the problem. Logged by a pass-through proxy sitting between
Claude Code and `api.anthropic.com`, on the same requests whose usage the client then declined to
display:


upstream sent Anthropic-Ratelimit-Unified-5h-Utilization: 0.09
upstream sent Anthropic-Ratelimit-Unified-5h-Status: allowed
upstream sent Anthropic-Ratelimit-Unified-5h-Reset: 1787137200
upstream sent Anthropic-Ratelimit-Unified-7d-Utilization: 0.16
upstream sent Anthropic-Ratelimit-Unified-7d-Status: allowed
upstream sent Anthropic-Ratelimit-Unified-7d-Reset: 1787468400
upstream sent Anthropic-Ratelimit-Unified-Status: allowed


From the JSON the client feeds its own `statusLine` command — same account, same model, both after
a successful `/v1/messages` round-trip:


// no base-URL override
"rate_limits": { "five_hour": { "used_percentage": 10, "resets_at": 1787137200 },
                 "seven_day": { "used_percentage": 16, "resets_at": 1787468400 } }

// ANTHROPIC_BASE_URL=http://127.0.0.1:8088  (pass-through proxy to api.anthropic.com)
"rate_limits": null

Steps to Reproduce

  1. Log in with a subscription account (/login). Launch claude, send a prompt, run /status

the 5-hour and 7-day usage meters are shown.

  1. Save a pass-through proxy that changes nothing except adding a log line — proxy.go:

```go
package main

import ("log"; "net/http"; "net/http/httputil"; "strings")

func main() {
p := &httputil.ReverseProxy{
Rewrite: func(r *httputil.ProxyRequest) {
r.Out.URL.Scheme, r.Out.URL.Host, r.Out.Host = "https", "api.anthropic.com", "api.anthropic.com"
},
FlushInterval: -1,
ModifyResponse: func(resp *http.Response) error {
for k, v := range resp.Header {
if strings.Contains(strings.ToLower(k), "ratelimit") {
log.Printf("upstream sent %s: %s", k, strings.Join(v, ","))
}
}
return nil
},
}
log.Fatal(http.ListenAndServe("127.0.0.1:8088", p))
}
```

  1. go run proxy.go &
  1. Launch Claude Code through it, same account:

``bash
ANTHROPIC_BASE_URL=http://127.0.0.1:8088 \
ANTHROPIC_AUTH_TOKEN="$(jq -r .claudeAiOauth.accessToken ~/.claude/.credentials.json)" \
claude
``

  1. Send a prompt, then run /status. The usage meters are gone, and rate_limits is null

in the statusline payload.

  1. Check the proxy's log: the anthropic-ratelimit-unified-* headers arrived on that very

request.

  1. Control — the trigger is the URL's value, not the proxy. Relaunch with

ANTHROPIC_BASE_URL=https://api.anthropic.com: the meters are back.

Claude Model

Opus

Is this a regression?

No, this never worked

Last Working Version

_No response_

Claude Code Version

2.1.235 (Claude Code)

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

Terminal.app (macOS)

Additional Information

Measured across five configurations on one host and one account, reading
context_window.context_window_size and rate_limits from the statusline JSON:

| Configuration | Context | rate_limits |
| --- | --- | --- |
| No base-URL override | 1,000,000 | populated |
| ANTHROPIC_BASE_URL=https://api.anthropic.com (official value, explicit) | 1,000,000 | populated |
| ANTHROPIC_BASE_URL=http://127.0.0.1:8088 (pass-through proxy) | 200,000 | null |
| Pass-through proxy + --model 'claude-opus-5[1m]' | 1,000,000 | null |
| Same proxy reached by DNS/hosts redirection, base URL unset, TLS terminated with a locally trusted CA | 1,000,000 | populated |

The last row is the useful one for scoping a fix: with the identical proxy in the identical
position, reached by redirecting api.anthropic.com at the resolution layer instead of by
overriding the base URL, everything works. Nothing about being proxied breaks the feature — only
the configured URL string does.

On the context column, for completeness and not as a second ask: the same override also drops
the account's 1M window to 200k. That half is already known — #68522 covers gateway model ids, and
CLAUDE_CODE_MAX_CONTEXT_TOKENS is documented for it, though per the docs an id starting with
claude- needs DISABLE_COMPACT set too, which is a steep price. --model 'claude-opus-5[1m]'
restores the window through the proxy and is the better workaround. There is no equivalent
workaround for the usage meters, which is why only that half is filed here.

Impact. Anyone whose Claude Code traffic is proxied on the way to Anthropic — corporate egress
proxies, audit and observability gateways, token-compression proxies (#72749), and sandboxing
tools that deliberately keep the credential off the machine running the agent. In all of them the
traffic terminates at Anthropic with a genuine subscription credential and the account is entitled
to the feature; the user simply loses their usage display, with no message and no obvious way to
connect the loss to the proxy.

View original on GitHub ↗