Errors
Every GLM 5 API error code in one table, with the HTTP status behind it, which ones are worth retrying, and how to debug context growth failures.
Non-streaming errors use an OpenAI-compatible object:
{
"error": {
"message": "Invalid API key provided.",
"type": "invalid_request_error",
"code": "invalid_api_key",
"param": null
}
}
This is the same shape most OpenAI-compatible SDKs expect: inspect error.code
for application logic and the HTTP status for retry decisions.
Error reference
| HTTP | Code | Meaning | Retry? |
|---|---|---|---|
| 400 | invalid_request_error | Malformed JSON, messages, tool arguments, or tool-result sequence. | No |
| 400 | context_length_exceeded | The request exceeds the selected model's context window, or max_completion_tokens exceeds what the model supports — GLM 5 forwards it as-is and relays the model's own rejection. | No |
| 400 | unsupported_parameter | The selected model does not support the requested feature. | No |
| 401 | invalid_api_key | The bearer key is missing, invalid, disabled, or deleted. | No |
| 402 | insufficient_quota | The API-eligible credit balance cannot cover the reservation. | No |
| 404 | model_not_found | The model ID is not in the public model list. | No |
| 413 | request_too_large | The request body exceeds 4 MB. | No |
| 429 | rate_limit_exceeded | The API key exceeded its requests-per-minute limit, or the upstream provider itself throttled the request. | Yes |
| 429 | daily_credit_limit_exceeded | The key's configurable spend limit (/settings/apikeys) was reached for the current window. | Yes, after reset_at |
| 500 | internal_error | An unexpected internal server error occurred. | Yes |
| 503 | service_unavailable | Public API access is temporarily unavailable. | Yes |
This table covers errors returned before a response begins. A stream: true
request that fails after streaming has started cannot carry a new top-level
HTTP status — the connection already committed to 200. See
Streaming errors for the codes that arrive inside the
SSE payload instead.
Retry policy
Retry only temporary failures:
429 rate_limit_exceeded: respect backoff and reduce concurrency.429 daily_credit_limit_exceeded: respect thereset_attimestamp in the error body before retrying.500,503: retry with exponential backoff.
Do not automatically retry 400, 401, 402, 404, or 413. Fix the
request, credentials, balance, or model selection first.
For context_length_exceeded, remove or summarize older messages, reduce tool
definitions, or lower max_completion_tokens — GLM 5 does not clamp this
value itself, so a very large request fails with whatever the underlying
model returns for its own limit. Context and output limits can vary by model.
Failed requests are reconciled so the reservation is refunded.
async function withBackoff<T>(operation: () => Promise<T>): Promise<T> {
let delay = 500;
for (let attempt = 0; attempt < 4; attempt += 1) {
try {
return await operation();
} catch (error: any) {
const status = error?.status;
if (![429, 500, 503].includes(status) || attempt === 3) {
throw error;
}
await new Promise((resolve) => setTimeout(resolve, delay));
delay *= 2;
}
}
throw new Error('Unreachable');
}
Streaming errors
Every synchronous rejection in the table above (invalid_api_key,
insufficient_quota, daily_credit_limit_exceeded, and so on) is returned
before the stream opens, as a normal HTTP error response — those work with
error?.status the way withBackoff above expects, whether or not the
original request had stream: true.
Once a stream: true response has begun sending data: chunks, the HTTP
status is already committed to 200 and cannot change. A failure at that
point instead arrives as a terminal error object inside the stream, and the
connection then closes:
data: {"error":{"message":"Internal server error.","type":"server_error","code":"internal_error","param":null}}
Two codes only ever appear this way, never as a top-level HTTP status:
| Code | Meaning | Retry? |
|---|---|---|
stream_timeout | The stream exceeded its 90-second lifetime — usually very slow model latency under load, or (less often) a very large request. | Yes |
client_cancelled | Your own client disconnected or aborted the request before it finished. | N/A (caused by the client) |
Check the error.code field of the SSE payload to tell these apart from a
genuine internal_error: a request that keeps hitting stream_timeout needs
a smaller request, not a retry loop against an unhealthy backend.
Under load, GLM models can take 20–30 seconds to emit their first token. GLM 5 routes each request to the lowest-latency provider and, if nothing has arrived after 25 seconds, transparently retries once on a different route before the 90-second lifetime applies. Set your HTTP client's read timeout to at least 90 seconds for streaming requests; a client-side timeout of 30 or 60 seconds will cancel requests that would have succeeded.
Diagnose growing-context failures
If a long-running client starts returning 402 insufficient_quota, inspect:
- The most recent
usage.prompt_tokens. - Whether the client resends all previous messages.
- The requested
max_completion_tokens. - The remaining API-eligible credit balance (
api_eligible_creditsin the 402 body, or Available for Public API on/settings/apikeys) — this is smaller than the total balance when part of it comes from free trial or welcome credits. Yearly subscription credits and referral rewards are API-eligible after the first purchase. See Billing and limits.