Trang này chưa được dịch sang Tiếng Việt. Đang hiển thị bản gốc tiếng Anh.
Errors and debugging
The status code / `error_type` pairing
Every /api/v1 error body has the same shape, on every path.
{
"error": {
"code": 404,
"message": "요청을 처리할 수 있는 엔드포인트가 없습니다.",
"metadata": { "error_type": "no_endpoints_found", "models": ["google/gemma-4-26b-a4b"] }
}
}error.codeis always equal to the HTTP status code. They never disagree.error.messageis a human sentence. The wording can change without notice, so do not branch on it.error.metadata.error_typeis the machine-readable value. Branch on that.
Status codes and error_type
| Status | error_type | Raised when |
|---|---|---|
| 400 | invalid_request | Schema violation: body is not a JSON object, messages missing, a message without role, /generation called without id |
| 400 | model_not_found | Unknown model id |
| 401 | invalid_api_key | Key not found, revoked, Authorization header missing, or wrong key kind |
| 401 | expired_api_key | The key is past its expires_at |
| 402 | insufficient_credits | Balance below the debt floor, or the key is suspended for lack of credit |
| 402 | key_limit_exceeded | The spend limit set on the key was exceeded |
| 403 | key_suspended | An administrator suspended the key. Topping up will not clear it |
| 404 | no_endpoints_found | The candidate chain came out empty |
| 404 | not_supported | Unimplemented path, endpoints lookup for an unknown model, or a generation that does not exist or is not yours |
| 408 | timeout | The upstream did not answer within the time limit |
| 429 | rate_limit_exceeded | Request rate limit exceeded |
| 502 | provider_error | Every candidate in the chain failed upstream |
| 503 | model_loading | A local GPU slot is starting, or could not start within its budget |
| 500 | server | Anything else. Details stay in the server log only |
Extra fields in metadata
error_type | Additional fields |
|---|---|
model_not_found | model — the id we could not find |
insufficient_credits | balance_krw — current balance in won |
key_limit_exceeded | limit_krw, usage_krw |
no_endpoints_found | models — the models that were requested |
not_supported | path — the missing path (on the unimplemented-path catch-all) |
timeout | timeout_sec |
provider_error | provider_code — the status the upstream returned |
model_loading | retry_after_sec |
Any response carrying retry_after_sec also gets the standard Retry-After header, so you can back off correctly without parsing metadata.
Error handling in practice
import os, time, requests
def call(payload, attempts=3):
for attempt in range(attempts):
response = requests.post(
"https://openrouter.myip.co.kr/api/v1/chat/completions",
headers={"Authorization": f"Bearer {os.environ['MYIP_API_KEY']}"},
json=payload,
timeout=650,
)
if response.ok:
return response.json()
body = response.json()
error_type = body["error"]["metadata"]["error_type"]
# Needs a top-up, a fix, or an administrator. Retrying will not help.
if error_type in {"invalid_api_key", "expired_api_key", "key_suspended",
"insufficient_credits", "key_limit_exceeded",
"invalid_request", "model_not_found", "not_supported"}:
raise RuntimeError(f"{response.status_code} {error_type}: {body['error']['message']}")
# Worth waiting and trying again.
if error_type in {"model_loading", "rate_limit_exceeded", "timeout", "provider_error"}:
wait = int(response.headers.get("Retry-After", 2 ** attempt))
time.sleep(wait)
continue
raise RuntimeError(f"{response.status_code} {error_type}")
raise RuntimeError("out of retries")Errors during a stream
Once a stream has started (the first byte is out), the status code can no longer change. The error therefore arrives inside an SSE chunk.
data: {"id":"gen-…","object":"chat.completion.chunk","model":"google/gemma-4-26b-a4b","provider":"MyIP Local GPU","error":{"code":502,"message":"upstream disconnected","metadata":{"error_type":"provider_error"}},"choices":[{"index":0,"delta":{"content":""},"finish_reason":"error"}]}
data: [DONE]Even on HTTP 200, check chunks for an error field. Details are in Streaming.
Why 503 model_loading happens
We serve models on our own GPU farm. If the GPU slot for a model is down when your request arrives, the gateway wakes it and waits. When it cannot come up within its start-up budget (which varies per model and comes from that slot's configuration) and no other candidate can take the request, you get 503 model_loading.
HTTP/1.1 503 Service Unavailable
Retry-After: 300
X-MyIP-Currency: KRW{
"error": {
"code": 503,
"message": "로컬 모델을 기동하는 중입니다. 잠시 후 다시 시도하세요.",
"metadata": { "error_type": "model_loading", "retry_after_sec": 300 }
}
}Wait for Retry-After and call again — start-up is already in progress, so the retry usually succeeds. The value differs per model, so read the header rather than hard-coding it. Background is in Local GPU models.
502 provider_error and the candidate chain
One request may try several candidates in order. Before the first byte is sent, a failed candidate is dropped and the next is tried. 502 is returned only when every candidate in the chain has failed; metadata.provider_code holds the status the last candidate returned.
What was tried, and how many times, is recorded in provider_responses on GET /generation. Failed requests are recorded too — at zero cost, with no ledger entry.
Identifiers to debug with
Everything you need to narrow a problem down is in the response headers.
| Header | Use |
|---|---|
X-MyIP-Request-Id | Ties together every candidate attempt of one request. Present on error responses too |
X-MyIP-Generation-Id | The /generation lookup key: tokens, cost and attempt history |
X-MyIP-Model / X-MyIP-Provider | The candidate that actually answered |
curl -i https://openrouter.myip.co.kr/api/v1/chat/completions \
-H "Authorization: Bearer $MYIP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"google/gemma-4-26b-a4b","messages":[{"role":"user","content":"hi"}]}' \
| grep -i '^x-myip'If you get 404 not_supported
You called a path we do not implement. The body names it.
{
"error": {
"code": 404,
"message": "Endpoint not supported on MyIP OpenRouter",
"metadata": { "error_type": "not_supported", "path": "/api/v1/embeddings" }
}
}The full list is in Unsupported endpoints.
Cập nhật lần cuối 5 thg 9, 2026