Errors

Handle GLM 5 API validation, authentication, quota, and server errors.

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 and OpenRouter-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 upstream model rejected the request because it exceeds its context window.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 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.Yes
500internal_errorAn unexpected server or provider error occurred.Yes
503service_unavailablePublic API access is temporarily unavailable.Yes

Retry policy

Retry only temporary failures:

  • 429: respect backoff and reduce concurrency.
  • 500: retry with exponential backoff.
  • 503: retry later.

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. This limit comes from the selected upstream model rather than a GLM 5 application-level token cap. 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

After a streaming response has begun, an error arrives inside the SSE stream:

data: {"error":{"message":"Internal server error.","type":"server_error","code":"internal_error","param":null}}

Handle both the initial HTTP status and error objects received during the stream.

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 GLM 5 credit balance.

See Context and cost control.