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

HTTPCodeMeaningRetry?
400invalid_request_errorMalformed JSON, messages, tool arguments, or tool-result sequence.No
400context_length_exceededThe 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
400unsupported_parameterThe selected model does not support the requested feature.No
401invalid_api_keyThe bearer key is missing, invalid, disabled, or deleted.No
402insufficient_quotaThe API-eligible credit balance cannot cover the reservation.No
404model_not_foundThe model ID is not in the public model list.No
413request_too_largeThe request body exceeds 4 MB.No
429rate_limit_exceededThe API key exceeded its requests-per-minute limit, or the upstream provider itself throttled the request.Yes
429daily_credit_limit_exceededThe key's configurable spend limit (/settings/apikeys) was reached for the current window.Yes, after reset_at
500internal_errorAn unexpected internal server error occurred.Yes
503service_unavailablePublic 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 the reset_at timestamp 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:

CodeMeaningRetry?
stream_timeoutThe stream exceeded its 90-second lifetime — usually very slow model latency under load, or (less often) a very large request.Yes
client_cancelledYour 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:

  1. The most recent usage.prompt_tokens.
  2. Whether the client resends all previous messages.
  3. The requested max_completion_tokens.
  4. The remaining API-eligible credit balance (api_eligible_credits in 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.

See Context and cost control.