Error reference: Claude Code and Codex on a third-party API
The same error line often has completely different causes when you go direct versus through a gateway. This reference is organised in five layers — network, auth, protocol, model, context — with a copy-paste probe and a decision rule for each.
How to use this page
Do not start by searching the error text. Start by working out which layer failed. Almost every AI-client error comes from one of five:
- Network: the request never left your machine
- Auth: it arrived, but the key was rejected
- Protocol: the key was fine, the path or format was not
- Model: the protocol worked, the model does not exist
- Context: the model is running, the input is too long
Layering matters because each layer has a completely different fix, and the error text rarely tells you which one you are in.
Diagnose by HTTP status
These commands check the model list and three protocols, showing the HTTP status of each request:
Set your own KimiSeek API key in the same terminal that will run curl, replacing the placeholder. A credential configured in your client does not automatically populate this shell variable:
# Replace the placeholder with your own key from the dashboard.
export KIMISEEK_API_KEY="ks-your-key"# Inspect each HTTP status and error body; a model list does not prove sufficient balance.
# 1. Is the key valid at all? (lists models)
curl -sS --max-time 30 -w '\nHTTP %{http_code} /v1/models\n' https://api.kimiseek.app/v1/models \
-H "Authorization: Bearer ${KIMISEEK_API_KEY:?Set KIMISEEK_API_KEY before running this command}"
# 2. OpenAI Chat Completions
curl -sS --max-time 30 -w '\nHTTP %{http_code} /v1/chat/completions\n' https://api.kimiseek.app/v1/chat/completions \
-H "Authorization: Bearer ${KIMISEEK_API_KEY:?Set KIMISEEK_API_KEY before running this command}" \
-H "Content-Type: application/json" \
-d '{"model":"deepseek-v4-pro-0813","messages":[{"role":"user","content":"ping"}],"max_tokens":8}'
# 3. Anthropic Messages (the protocol Claude Code speaks)
curl -sS --max-time 30 -w '\nHTTP %{http_code} /v1/messages\n' https://api.kimiseek.app/v1/messages \
-H "x-api-key: ${KIMISEEK_API_KEY:?Set KIMISEEK_API_KEY before running this command}" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{"model":"deepseek-v4-pro-0813","max_tokens":8,"messages":[{"role":"user","content":"ping"}]}'
# 4. OpenAI Responses (the protocol Codex speaks)
curl -sS --max-time 30 -w '\nHTTP %{http_code} /v1/responses\n' https://api.kimiseek.app/v1/responses \
-H "Authorization: Bearer ${KIMISEEK_API_KEY:?Set KIMISEEK_API_KEY before running this command}" \
-H "Content-Type: application/json" \
-d '{"model":"deepseek-v4-pro-0813","input":"ping","max_output_tokens":16}'Read the HTTP status after each response and its error.code, error.type, and message. The failed step alone cannot establish protocol support. A 200 model list validates the key, not the balance: a zero-balance account can receive 200 at step 1 and 402 at step 2.
| Status or error | Interpretation | Next action |
|---|---|---|
| 200 with the expected response structure | This endpoint request worked; not all tool capabilities are verified | Test client configuration and real tool calls next |
| 401 / 403 | Credentials, key limits, or model access permissions | Check key validity, enabled status, expiry, limits, and upstream authorization |
402 / insufficient_balance | Insufficient account balance | Add funds and retry; protocol settings need no change |
400 / 404 with model_not_found, not_found_error, or a missing-model message | Incorrect or disabled model ID, or missing upstream model access | Select the full ID from the model list and verify channel access |
| 400 with an invalid-parameter message | Incompatible request fields or model limits | Check messages, tools, and token limits against the error body |
| 404 explicitly naming a missing route or endpoint | Incorrect path or an endpoint the gateway does not provide | Check Base URL and /v1, then verify protocol support; 404 alone does not distinguish a missing model from a missing route |
| 429 | Rate limit, quota, or upstream overload | Inspect the error, wait before retrying, or adjust usage |
| 5xx | Temporary gateway or upstream failure | Keep the error and request ID, then retry later |
| HTTP 000 / curl connection or timeout error | No HTTP response; each probe waits at most 30 seconds | Check DNS, proxies, and the network; a probe timeout does not prove a missing protocol |
Claude Code side
No credentials
Invalid API key · Please run /loginThis means Claude Code found no credentials at all. Check whether ANTHROPIC_AUTH_TOKEN is set in the shell that launched it — a classic mistake is exporting in one terminal and starting the client in another.
401 unauthorised
API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"invalid api key"}}Causes, in order of likelihood:
- The key was copied with a trailing space or newline
- The key was revoked or its quota is exhausted
ANTHROPIC_API_KEYis set but empty, so the client falls back to a login session
403 forbidden
API Error: 403 {"type":"error","error":{"type":"forbidden","message":"invalid x-api-key"}}Going direct, this usually means the key is invalid. Through a gateway, the more common cause is a header mismatch: some gateways only accept Authorization: Bearer, others only x-api-key. KimiSeek accepts both, but if you have another proxy in between, the header may be rewritten.
model not found
API Error: 400 {"type":"error","error":{"type":"invalid_request_error","message":"model: deepseek-v4-flash-0731 not found"}}Two possibilities: a misspelled model name, or a retired model. A retired model id keeps returning not found instead of saying it was retired, which is the most time-consuming trap here — you end up auditing configuration when the real answer is that the model was replaced.
Replace it with a real id from the models page.
The stream cuts out
API Error: stream disconnected before completion: stream closed before completionA streaming connection was cut mid-flight. Check in this order:
- Whether a local HTTP proxy (
HTTPS_PROXY) is intercepting - Whether the corporate network times out long responses
- Whether a per-request server limit fired
The upstream request timeout is 600 seconds for /v1/messages (Claude Code) and 175 seconds for /v1/responses (Codex). Clients or intermediate proxies may disconnect earlier; diagnose the failure using the actual endpoint and error details.
Context overflow
API Error: 400 {"type":"error","error":{"type":"invalid_request_error","message":"prompt is too long: 210000 tokens > 200000 maximum"}}Note that the 200000 here is the client's or the model's limit, not necessarily what you expected. On DeepSeek V4 Pro the real limit is 1M, so seeing 200000 means the request did not reach the model you think it did, or the client truncated at Claude's spec.
Codex side
401 Missing bearer
■ unexpected status 401 Unauthorized: Missing bearerenv_key in config.toml is only a variable name; the value has to be in the environment. This error is "you named the variable, but it is empty".
404 Not Found
■ unexpected status 404 Not FoundEight times out of ten the base_url is missing /v1. Codex builds base_url + "/responses", so without /v1 it hits a web page.
After checking base_url, inspect the response body for a missing model as well. If the gateway truly lacks /v1/responses, use a Responses-compatible gateway or translation layer; current Codex rejects wire_api = "chat". See the Codex guide.
Stream interruption
■ stream disconnected before completionSame streaming problem as Claude Code, but Codex is more sensitive to it because its execution loop depends on a complete event stream. On an unstable network, change networks rather than retrying.
Two typical network failures
fetch failed
ECONNREFUSED 127.0.0.1:7890fetch failed is Node's generic network error and carries no information by itself. The useful line is ECONNREFUSED 127.0.0.1:7890 — a local port like that means a local proxy took over the request and the proxy is not running or its rules are wrong.
This is the failure most often misdiagnosed as "the gateway is down". The test: if curl works and the client does not, the client's shell environment differs from curl's.
Same error, different cause
This is the mental model that matters most with a gateway:
| Error | Going direct | Through a gateway |
|---|---|---|
invalid x-api-key | The key is invalid | The header name is unrecognised, or an intermediate proxy rewrote it |
model not found | Wrong model name | The gateway's model map lacks this id, or it is retired |
stream disconnected | Official service hiccup | Local proxy, corporate network, or gateway timeout |
prompt is too long | Over 200K | The gateway routed to an upstream with a smaller context |
| 401 | Bad key | Key is fine, the environment variable never reached the client |
What to include when you ask for help
Four things, all of them, or nobody can diagnose it:
- The full error line, not a cropped screenshot
- The result of the layered curl probe — which of the four steps failed
- Client versions (
claude --version,codex --version) - The model id and Base URL in use, with the key redacted
Verification
- Verified: 2026-10-26
- Error examples help locate the failing layer; exact wording can vary by client version. Include your installed version when reporting a problem. The Codex configuration was checked with 0.154.0.
FAQ
curl works, the client does not. Why?
Most often the environment variable is not in the same shell. The client reads its own process environment, so exporting in another terminal does nothing. Confirm echo $ANTHROPIC_AUTH_TOKEN has a value in the shell that launched the client.
What is the real difference between 403 and 401?
401 is 'I do not know who you are'; 403 is 'I know who you are and you may not do this'. Through a gateway, 403 is usually a header or routing policy problem, while 401 is usually the key itself or an environment variable.
Context overflow says 200000, but the model claims 1M. Why?
It means the request did not reach the model you think it did. Either the model id fell back to a default, or the client truncated at Claude's spec. Check the id with /v1/models, then check the context window setting in the client.
Will retrying fix a broken stream?
Usually not. A broken stream is a connection-layer problem, and a retry just repeats the same failure. Check the proxy and network first, then split long jobs into smaller ones.