Skip to content

Troubleshooting

Common shunt errors and how to fix them.

Updated View as Markdown
Symptom Cause / Fix
Sentry: upstream SSE stream was cut before a terminal event A streaming response ended without a terminal event. Read the event’s cut_kind tag: transport_error means the body read failed (upstream_error has the message), eof means the upstream closed cleanly mid-message, marker means shunt detected the cut and synthesized a completion for the client. The sse_events, bytes_forwarded, last_event_type, elapsed_ms, and ttft_ms extras say how far the response got and how long it took.
ChatGPT auth not found; run codex login shunt can’t read ~/.codex/auth.json. Run codex login.
authentication_error on a mapped model Expired/absent provider credential — re-run codex login, or export OPENAI_API_KEY. shunt surfaces the backend’s real detail message.
400 … model is not supported when using Codex with a ChatGPT account You used a -codex slug (or one your account isn’t entitled to). Use an entitled slug from models.json (e.g. gpt-5.6-sol, gpt-5.5) or set upstream_model.
/model doesn’t list your model For gpt-* ids use ANTHROPIC_CUSTOM_MODEL_OPTION; discovery only surfaces claude/anthropic-prefixed ids.
opus selects Opus 4.7 / sonnet selects Sonnet 4.6 Claude Code’s built-in alias table pins those tiers for gateway sessions. Pin the tier client-side with ANTHROPIC_DEFAULT_OPUS_MODEL=claude-opus-5, or remap the id in shunt — see Model Aliases.
Context window shows 200K on Opus/Fable Claude Code only trusts a model’s native 1M window when the base URL is api.anthropic.com. Select opus[1m] / fable[1m] — see Model Aliases.
Fable missing from /model, or claude-fable-5 falls back to Opus Fable is filtered out behind a plain ANTHROPIC_BASE_URL. Set ANTHROPIC_DEFAULT_FABLE_MODEL=claude-fable-5, or use gateway login — see Model Aliases.
Discovery never fires It’s gated on a gateway credential (ANTHROPIC_AUTH_TOKEN, API key, or apiKeyHelper) plus CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1. Debug with claude --debug[gatewayDiscovery] lines.
config check failed Run shunt check for the exact reason (bind address, unknown provider in a route, wrong adapter/auth).
Prompt caching uses the 5-minute TTL Check which setup you’re in first. Behind a plain ANTHROPIC_BASE_URL, “subscription users within included usage receive 1-hour TTL automatically” and only those “drawing on usage credits” need ENABLE_PROMPT_CACHING_1H=1 (1-hour cache writes bill “at a higher rate”; FORCE_PROMPT_CACHING_5M=1 forces 5 minutes back). On a gateway login session the client omits the extended-cache-ttl beta outright, so the 5-minute TTL is expected there. See Client Environment Variables.
Remote Control or voice dictation unavailable Expected behind a gateway credential, not a shunt bug. Both are unavailable while ANTHROPIC_AUTH_TOKEN, ANTHROPIC_API_KEY, or an apiKeyHelper is set, and as of Claude Code v2.1.196 Remote Control is also disabled while ANTHROPIC_BASE_URL points at a non-Anthropic host. Run claude doctor to see which variable to unset — see Features a gateway credential turns off.
Fast mode reports a connectivity error while inference works The fast-mode availability check calls api.anthropic.com directly instead of following ANTHROPIC_BASE_URL, so it never reaches shunt. On a network that blocks direct egress to api.anthropic.com it fails while gateway inference keeps working. The WebFetch domain safety check bypasses the base URL the same way — see What a base URL does not redirect.
Claude Code asks you to log in Set an Anthropic credential (ANTHROPIC_AUTH_TOKEN / login) that shunt can forward for unmapped models. A base URL alone is not a credential.
Effort stuck at medium on a mapped model Check the model id first: ids on Claude Code’s legacy effort deny list (claude-sonnet-4-5, claude-haiku-4-5) never send output_config.effort, and no environment variable overrides that — remap to a different id. Otherwise confirm an effort level is actually set (/effort or CLAUDE_CODE_EFFORT_LEVEL). CLAUDE_CODE_ALWAYS_ENABLE_EFFORT=1 does not help here; verified against v2.1.224, a custom gateway id already sends effort without it. See Effort & Context.
Tool search inactive on a mapped model (every tool’s schema sent each turn) Set ENABLE_TOOL_SEARCH=true. Claude Code auto-disables optimistic tool search behind a non-Anthropic base URL; shunt forwards tool_reference blocks and reveals deferred schemas on demand — see ChatGPT / Codex → Tool search.
400 Deferred custom tools are only supported on Anthropic models… Received stealth/ox-alpha (or another non-Claude slug) Claude Code sent defer_loading / a tool_search_tool_* on a non-Anthropic Messages model. shunt strips those fields for non-claude* / non-anthropic/* upstream ids before forwarding; Anthropic slugs on OpenRouter keep the protocol.
Tool search works but reclaims no context (still paying the text shim’s cache-invalidation cost) Native tool_search defaults (“auto”) to known-good hosts only — the ChatGPT/Codex backend and api.openai.com — plus the flavor/model gates (stock OpenAI/ChatGPT-Codex flavor, gpt-5.4+ model). A custom OpenAI-compatible endpoint (LiteLLM, vLLM, OpenRouter, self-hosted) is not auto-enabled; set tool_search = true on it once you’ve confirmed it implements tool_search items. If you expected native on a known host and it’s still shimming, confirm you haven’t set tool_search = false — see ChatGPT / Codex → Tool search → Native protocol.
Session stuck after a context-length error on a mapped model shunt rewrites upstream overflow errors to prompt is too long … so Claude Code auto-compacts and retries — see Context overflow recovery. If it recurs every few turns, lower CLAUDE_CODE_MAX_CONTEXT_TOKENS to the model’s real window.
Stream dies behind Cloudflare (524) Keep sse_keepalive_seconds at its default (30) instead of 0.
401 on mapped models on a shared gateway Missing/invalid client token — set ANTHROPIC_AUTH_TOKEN=<token> (accepted as Authorization: Bearer, pool-only gateways) or ANTHROPIC_CUSTOM_HEADERS="x-shunt-token: <token>" (recommended when passthrough models are mixed in, so each caller’s real credential keeps a slot of its own — a client token that does land in Authorization / x-api-key is cleared from that slot rather than forwarded); see Sharing a Gateway.
429 on Anthropic-adapter models Check rate_limit_kind in the gateway log. quota (has retry-after / anthropic-ratelimit-* headers) is a real rate limit — back off or reduce parallel load. client-shape-rejection (OAuth request, neither header, body just "Error") means api.anthropic.com rejected a subscription-OAuth request that doesn’t look like Claude Code — non-Claude-Code clients must use an API key instead of an OAuth token. Claude Code’s auto-mode permission classifier is the one first-party request that omits the identity block upstream looks for; shunt restores it on that request alone, so auto mode no longer fails closed with “model temporarily unavailable”. Every other request keeps byte-for-byte passthrough. no-ratelimit-headers (non-OAuth credential) is a provider 429 without rate-limit metadata — treat it as quota.
503 overloaded_error on a shared gateway The gateway is at its inbound concurrency cap and shed the request instead of queueing it (body message too many requests are already in flight, with Retry-After: 1). This is shunt’s own admission control, not an upstream 503 — an upstream one is relayed with the provider’s own message. Retry after the delay, reduce parallel load, or raise max_concurrent_requests and restart (the limit is fixed at startup).

For the full gateway troubleshooting table, see Connect Claude Code to an LLM gateway.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close