`claude setup-token` tokens rejected with "API Error: 400 status code (no body)" on first request — Max 20x account, fresh mints, reproduces locally and in CI
Summary
Every long-lived OAuth token minted by claude setup-token (correct sk-ant-oat01- prefix) is rejected by the API with API Error: 400 status code (no body) on the very first request — while interactive Claude Code on the same machine, same account, works perfectly. Reproduces identically in GitHub Actions (claude-code-action@v1, claude_code_oauth_token input) and locally (CLAUDE_CODE_OAUTH_TOKEN=<token> claude -p "..."). Multiple fresh mints over several hours on 2026-08-15 (~18:00–20:00 UTC) all fail the same way.
Environment
- Account: Claude Max 20x (
organizationType: claude_max,billingType: stripe_subscription, subscription active since 2026-02) - Local: Claude Code 2.1.232 on Windows 11 (Git Bash) — interactive use works
- CI: ubuntu-latest,
anthropics/claude-code-action@v1(also reproduced with the CLI pinned to 2.1.232 viapath_to_claude_code_executable) - Timing note: mints occurred hours after the Aug 14 20:00 – Aug 15 00:11 UTC OAuth incident on status.claude.com was marked resolved
Failure signature
{"type":"system","subtype":"init","message":"Claude Code initialized","model":"claude-sonnet-5"}
{"type":"result","subtype":"success","is_error":true,"duration_api_ms":0,"num_turns":1,
"total_cost_usd":0,"input_tokens":0,"api_error_status":400,
"result":"API Error: 400 status code (no body)"}
Assistant message model is <synthetic>, is_api_error_message: true, error: "unknown". Fails in ~250 ms at zero cost — the first request never gets a body back.
Ruled out (each tested)
- Token value corruption — token piped via stdin with CR/whitespace stripping; multiple careful re-pastes; same result.
- Wrong token type — confirmed
sk-ant-oat01-prefix (notsk-ant-api03/sk-ant-sid01). - CI environment — reproduces locally with only
CLAUDE_CODE_OAUTH_TOKENset; action debug logs show the token delivered to the execute phase, no Bedrock/Vertex/base-URL overrides,anthropic_api_keyempty. - Model — identical 400 with default
claude-sonnet-5and explicit--model claude-haiku-4-5-20251001. - CLI version — identical 400 on 2.1.233 (CI default) and 2.1.232 (pinned; the exact version that works interactively on the same machine).
- Account mismatch —
setup-tokenbrowser approval performed in the sameclaude.aiaccount the CLI is logged into (verified viaoauthAccountmetadata). - Stale mint / revocation by newer mints — every attempt used the newest mint, pasted immediately.
- Workspace API-key policy (#54502) — not applicable; consumer
claude_maxorg, the workspace setting does not exist.
Expected
A freshly minted setup-token token authenticates for user:inference on a Max account, as documented for CI use.
Possibly related
- anthropics/claude-code-action#1316 (oat01 token 400s in action, works locally — our case fails in BOTH, so possibly a different or wider issue)
- anthropics/claude-code-action#1281 (Max-plan OAuth token failures)
- The Aug 14–15 OAuth incident — is token issuance fully recovered?
Ask
Is long-lived token issuance currently degraded for Max accounts, and is there server-side logging for the 400-no-body path that can identify what the request is missing?
3 Comments
Update — error-layer calibration narrows this to request construction, not token validity:
CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-garbage claude -p "hi") →Failed to authenticate. API Error: 401 OAuth access token is invalid.API Error: 400 status code (no body)So freshly minted tokens are recognized as valid credentials (they do not hit the 401 invalid-token path) — the request built in env-token mode is then rejected with a bodyless 400 at some later validation layer. Interactive keychain auth on the same account/machine works, so whatever context the profile-aware path attaches (billing/beta headers?) appears to be missing or mismatched in the
CLAUDE_CODE_OAUTH_TOKENpath.Possibly relevant account detail:
organizationType: claude_max, tierdefault_claude_max_20x,hasExtraUsageEnabled: true— if inference for extra-usage-enabled Max accounts requires billing context the env-token request path doesn't send, that would reproduce exactly this split (env-token 400 everywhere incl. CI; interactive fine).Reproduced identically on 2.1.232 and 2.1.233 (local and CI, ubuntu-latest and Windows/Git Bash).
I can confirm this issue is still reproducible on Windows with a freshly generated long-lived OAuth token.
Environment
Reproduction
The token was generated successfully with:
Claude Code reported:
The actual OAuth token is not included here.
The token was then supplied to the Claude process through
CLAUDE_CODE_OAUTH_TOKEN.Minimal test:
Result, consistently:
I also reproduced the same result when the environment variable was injected by a Windows launcher rather than set interactively.
Additional observations
/loginsession.This reproduction is on Claude Code 2.1.252, so the issue appears to persist beyond the 2.1.232/2.1.233 versions mentioned in the original report.
It would be useful if Claude Code could surface a request/correlation ID or the backend error body for this authentication failure so affected users can distinguish token-format, account-policy, and server-side issuance failures.
Additional diagnostic from my reproduction:
With the freshly generated
CLAUDE_CODE_OAUTH_TOKENinjected:returns:
Without the injected token, the same machine returns:
Therefore Claude Code is definitely detecting and selecting the long-lived OAuth token, and there is no competing stored login credential.
However:
still returns:
This appears to narrow the failure to the request/backend path after OAuth-token selection rather than local credential discovery or precedence.
No OAuth token or other credential is included in this report.