Skip to content

Troubleshooting ​

Start with the health endpoints, then work outward.

Health endpoints ​

All three are unauthenticated:

EndpointReturns
GET /api/healthAlways 200. status plus services.database (a SELECT 1) and services.redis (status, healthy, enabled; disabled when Redis is off). Also services.rate_limiting — informational, never degrades status: backend (redis = one shared window per deployment, memory = one window per process, so N workers enforce N times the configured limit), shared, and disabled (the rate_limit_disabled switch)
GET /api/health/ready200 {"status":"ready"} when healthy, otherwise 503 — use this for orchestrator readiness
GET /api/health/liveAlways 200 {"status":"alive"} — liveness only, no dependency checks

Startup failures ​

The process fails loudly rather than starting half-configured. Find the error in the container/console logs:

ErrorCause / fix
Migration error on bootDatabase unreachable, credentials wrong, or a failed migration. The port is never bound; fix the database and restart
Could not find alembic.iniRunning from an installation that lost alembic.ini (it must be in the CWD or repo root)
Redis ConfigurationError at bootREDIS_ENABLED=true but the server is unreachable — there is no silent degradation at startup
Invalid TRUSTED_PROXIES CIDRFix the value; startup validates it
Settings validation errore.g. DB_POOL_SIZE < 1, REDIS_TIMEOUT <= 0
Config validation errorA stored provider/model/user record is invalid — the message names the record

Symptom → cause → fix ​

SymptomCauseFix
401 authorization header missing / invalid authorization header formatNo key sent, or Authorization does not use BearerSend Authorization: Bearer sk-… or x-api-key: sk-…. Console JWTs do not work on /v1/*
429 too_many_auth_failures with Retry-AfterAPI-key IP lockout is enabled (off by default) and this address passed max_failed_api_key_attempts invalid keysWait out Retry-After; fix the key. Because the lockout is keyed by IP, one bad client blocks everyone sharing that address — on a dev machine, that is every request from 127.0.0.1. Turn it off under Settings → Security, or flip Disable Throttling (counters are in-process, so a restart clears them too)
403 model_not_allowedKey or user allowlist excludes the modelAdjust the allowlist, or use an allowed model. Remember: empty allowlist = deny all
404 model_not_foundModel name is not in the model mappingsAdd the mapping (or fix the name). Virtual models need smart routing enabled
500 configuration_error mentioning a virtual modelauto/fast/best used while smart routing is disabled, or on a non-chat endpointEnable smart routing, or use a concrete model name
429 rate_limit_exceededPer-key RPM cap or an auth bucketRaise rate_limit_rpm, or wait for the fixed 60 s window
429 budget_exceeded / user_budget_exceededKey or account budget exhaustedRaise the budget or reset it (account budgets only by an admin)
413 body_size_exceededBody above max_request_body_size_bytes (64 MiB default)Raise the limit or shrink the request
499 client_disconnected in logsClient/CDN gave up mid-requestUsually a CDN timeout — keep keepalive enabled, or stream instead of waiting on a long non-streaming call
Response arrives as 200 with an error JSON bodyKeepalive heartbeat mode had already committed 200 before the failureExpected tradeoff; check the body, and the real error is in the logs. See Reverse Proxy & TLS
Browser reports a CORS failure instead of a real statusAuth/body/rate-limit middleware run outside CORSReproduce with curl to see the true status; then fix the underlying error
Streaming request stalls with no dataUpstream silence; the proxy is sending : keep-alive comment framesThis is normal. If your reverse proxy buffers responses, disable buffering
Admin UI missing at / (API works)frontend/dist did not exist at startupRun uv run llm-proxy --build-frontend and restart
Logs screen shows rows but bodies are {"_bodies_disabled": true}Expected default: Log Input/Output is off, so every content payload (request/response bodies, upstream error bodies, MCP/web-search arguments and results) is scrubbed while the metadata row is still writtenTurn Log Input/Output on in Settings → Log Management to store bodies. x-log-full: true cannot re-enable bodies while the master switch is off
Logs screen shows {"_sampled_out": true} on some rows with body logging onBody Sampling Rate is below 1.0, so that request lost the draw. Distinct from the disabled marker on purposeRaise Body Sampling Rate to 1.0, or send x-log-full: true on the requests you need captured
Usage stats empty but logs existUsage and logs are written separatelyCheck the date range; usage records are pruned on the log retention window
503 redis_not_available on Responses endpointsRedis is not enabled, but stored responses need itEnable Redis, or avoid the response-storage endpoints
MCP server refuses to startDeny-by-default policy: its command or env var is not allowlistedAllowlist the exact command in Settings → Advanced → MCP Security (see MCP Servers)
MCP 403 Access denied to MCP serverKey allowlist excludes the serverUpdate the key's MCP allowlist
MCP returns 404 for a server that existsServer is not running (stopped/disabled, or crash at startup)Check status in the console; disable + re-enable to restart
MCP changes don't take effectA running server is not restarted by an updateDisable, then re-enable the server
web_search tool calls return web_search_tool_result_errorSearch backend unreachable / rate-limited / bad keyThe model still answers; check the Web Search log tab and the backend config
Smart routing picks unexpected modelsClassifier signals or mode weightsReview Settings → Advanced → Smart Routing; use routing diagnostics (verbose_routing_logs) and per-request feedback
Claude Code warns the session "isn't eligible" for no-charge auto modeThe upstream cannot run server-side auto-mode checksSee Claude Code auto mode below

Claude Code auto mode ​

Claude Code (v2.1.278+) with auto mode asks the upstream to run its safety checks by adding a safeguards request field and the dangerous-tool-use-2026-09-03anthropic-beta value; the upstream must answer with a safeguard_results response field (streamed: inside the terminal message_delta delta), keyed by tool-use id. When neither half comes back, Claude Code falls back to its own classifier — billed as token usage — and shows a notice the first time it would have checked an action.

Nothing breaks when this happens; auto mode keeps working.

  • Non-Anthropic upstreams cannot serve this at all — Ollama, vLLM, SGLang, and the third-party Claude-compatible providers (z.ai, Kimi, MiniMax, Moonshot, DeepSeek, Qwen) have no server-side check. The notice is expected on those routes.
  • An Anthropic-format upstream works when the fields survive end to end. This proxy's native Anthropic passthrough forwards safeguards, the full anthropic-beta value, and every response key verbatim; the converted path keeps safeguard_results too.
  • Silence the notice by setting CLAUDE_CODE_AUTO_MODE_SERVER=0 in the environment Claude Code starts from. It then never asks for server-side checks and the notice disappears.

To confirm which state a session is in, run /status in Claude Code and check the Auto mode server row: Enabled means the server is performing the checks, Disabled means the session has fallen back.

Getting more detail ​

  • Request id — every response carries X-Request-Id; search the Logs screen for it. Note that an inbound x-request-id is used as the tracing/routing id, while the response header is always the server-generated id.
  • Application logs — LOG_LEVEL=DEBUG (restart required) or --log-file.
  • Audit trail — admin operations and security events are in Logs → Audit Logs, with Verify Integrity to prove the chain is intact.
  • Provider failures — errors surface with the upstream status and message; 502 means provider/network/parse failure, 504 a timeout (upstream calls use a fixed 600 s read timeout with a 10 s connect; the provider timeout field is not applied).

MIT licensed