OAuth tokens require undocumented system prompt validation for non-Haiku models — returns generic 400

Resolved 💬 3 comments Opened Mar 29, 2026 by jalagrange Closed Apr 1, 2026

Summary

Anthropic's Messages API silently validates the system field when requests are authenticated with OAuth tokens (sk-ant-oat-*). For all models except Haiku, the API requires the system prompt to begin with the exact string:

You are Claude Code, Anthropic's official CLI for Claude.

This string must be either:

  • The entire first entry in a system array, OR
  • The start of a plain system string

Without it, the API returns HTTP 400 invalid_request_error with the unhelpfully generic message "Error". Haiku is exempt from this validation.

This requirement is undocumented, has no public guidance, and related issues are being auto-closed by bots without staff engagement.

Proof

All tests use the same OAuth token, headers, and model (claude-opus-4-6). The only variable is the system field.

No system prompt → 400

curl -s -X POST "https://api.anthropic.com/v1/messages" \
  -H "Authorization: Bearer $TOKEN" \
  -H "anthropic-beta: claude-code-20250219,oauth-2025-04-20" \
  -H "anthropic-version: 2023-06-01" \
  -H "user-agent: claude-cli/2.1.85 (external, cli)" \
  -H "x-app: cli" \
  -H "content-type: application/json" \
  -d '{"model":"claude-opus-4-6","max_tokens":50,"messages":[{"role":"user","content":"say hi"}]}'
{"type":"error","error":{"type":"invalid_request_error","message":"Error"}}
// HTTP 400

Identity concatenated into a single block → 400

# Same request but with:
"system": [{"type":"text","text":"You are Claude Code, Anthropic's official CLI for Claude. You help with tasks."}]
{"type":"error","error":{"type":"invalid_request_error","message":"Error"}}
// HTTP 400

Identity as separate first entry → 200 ✓

# Same request but with:
"system": [
  {"type":"text","text":"You are Claude Code, Anthropic's official CLI for Claude."},
  {"type":"text","text":"You help with tasks."}
]
{"model":"claude-opus-4-6","id":"msg_...","content":[{"type":"text","text":"Hi! 👋 How can I help you today?"}]}
// HTTP 200

Identity as plain string → 200 ✓

# Same request but with:
"system": "You are Claude Code, Anthropic's official CLI for Claude."
{"model":"claude-opus-4-6","id":"msg_...","content":[{"type":"text","text":"Hi! 👋 How can I help you today?"}]}
// HTTP 200

Model matrix (with correct system prompt)

| Model | Without identity | With identity |
|-------|-----------------|---------------|
| claude-opus-4-6 | 400 | 200 |
| claude-sonnet-4-6 | 400 | 200 |
| claude-haiku-4-5-20251001 | 200 | 200 |

Impact

This undocumented requirement affects every third-party consumer using Claude Max OAuth tokens outside the Claude CLI:

  • OpenClaw — the open-source AI gateway used by hundreds of self-hosted deployments
  • opencode-claude-auth — community OAuth bridge for OpenCode
  • Custom integrations — anyone using sk-ant-oat-* tokens with the Anthropic SDK

The community has been debugging this for weeks. Multiple issues have been filed:

  • #34412 — OAuth 500 on Sonnet/Opus (tagged invalid, no staff response)
  • #35269 — Opus/Sonnet silently blocked on MaxPlan
  • #8052 — Large thread about "Credential Restricted to Claude Code"
  • #24198 — "only authorized for use with Claude Code" error

All were auto-closed by bots or tagged invalid with no Anthropic staff engagement or explanation.

The asks

  1. Document the OAuth validation requirements publicly. If OAuth tokens require specific system prompt content, headers, and user-agent strings, publish this in the API docs so consumers can comply.
  1. Improve the error message. {"message":"Error"} gives zero debugging signal. A message like "OAuth tokens require a Claude Code system prompt identity" would save the community hundreds of hours of debugging.
  1. Engage with the community. Multiple issues about this have been filed over the past month. A single official comment explaining the requirements (or confirming this is intentional) would resolve dozens of open threads.

Environment

  • OAuth token: sk-ant-oat01-* (Claude Max subscription, setup token via claude setup-token)
  • Tested from: Ubuntu 24.04 server, curl 8.5.0
  • Models: claude-opus-4-6, claude-sonnet-4-6, claude-haiku-4-5-20251001
  • Headers: anthropic-beta: claude-code-20250219,oauth-2025-04-20, user-agent: claude-cli/2.1.85 (external, cli), x-app: cli

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗