> ## Documentation Index
> Fetch the complete documentation index at: https://dev-docs.altrum.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Handle errors

> Catch the AI Gateway's refusals in your application, retry the ones that pass, and show people a useful message for the rest.

The AI Gateway's errors look like your provider's errors, so the SDK you use raises them the same way. What changes is that some errors now come from your organization's own rules: a guardrail, a budget, a model nobody approved. Your application should tell those apart from a provider having a bad minute.

## Decide by code

Read the code from the error body (see [Errors](/api-reference/errors) for where each format puts it) and act on it:

| Codes | What happened | What your application should do |
| - | - | - |
| `rate_limited`, `request_limited`, `token_limited`, `organization_concurrency_limit` | A limit was reached for now. | Retry with backoff. |
| `guardrail_check_failed`, `upstream_unavailable` | Altrum or the provider could not complete it this time. | Retry with backoff. |
| `guardrail_blocked` | A guardrail stopped what was sent. | Do not retry the same text. Tell the person to change it. |
| `response_blocked` | A guardrail stopped the reply. | Do not retry the same request. Ask for something different. |
| `budget_exceeded` | A budget is used up until it resets. | Do not retry. Tell the person, and alert whoever owns the budget. |
| `model_blocked`, `provider_blocked`, `mcp_tool_blocked`, `access_blocked`, `ai_system_inactive` | Your organization's settings do not allow this. | Do not retry. Log it; a person must change the settings. |
| `virtual_key_required`, `access_not_found` | The key is missing or wrong. | Do not retry. Fix the configuration. |

The OpenAI and Anthropic SDKs already retry a 429 or a 5xx twice by default, with backoff. Raise `max_retries` if you need more, and let everything else fail fast.

## Example

<CodeGroup>
  ```python Python theme={null}
  import os
  import openai
  from openai import OpenAI

  client = OpenAI(base_url="https://api.altrum.ai/v1", api_key=os.environ["ALTRUM_VIRTUAL_KEY"], max_retries=4)

  def ask(text: str) -> str:
      try:
          reply = client.chat.completions.create(
              model="openai/gpt-4o-mini",
              messages=[{"role": "user", "content": text}],
          )
          return reply.choices[0].message.content
      except openai.APIStatusError as error:
          code = (error.body or {}).get("type") if isinstance(error.body, dict) else None
          request_id = error.response.headers.get("x-request-id")
          if code == "guardrail_blocked":
              return "That message can't be sent. Please remove any personal or sensitive details and try again."
          if code == "response_blocked":
              return "I can't answer that. Try asking in a different way."
          if code == "budget_exceeded":
              return "This assistant has reached its spending limit for now."
          raise RuntimeError(f"AI Gateway refused the request: {code} (reference {request_id})") from error
  ```

  ```typescript TypeScript theme={null}
  import OpenAI, { APIError } from "openai";

  const client = new OpenAI({ baseURL: "https://api.altrum.ai/v1", apiKey: process.env.ALTRUM_VIRTUAL_KEY, maxRetries: 4 });

  export async function ask(text: string): Promise<string> {
    try {
      const reply = await client.chat.completions.create({
        model: "openai/gpt-4o-mini",
        messages: [{ role: "user", content: text }],
      });
      return reply.choices[0].message.content ?? "";
    } catch (error) {
      if (!(error instanceof APIError)) throw error;
      const code = error.type;
      const requestId = error.headers?.["x-request-id"];
      if (code === "guardrail_blocked") return "That message can't be sent. Please remove any personal or sensitive details and try again.";
      if (code === "response_blocked") return "I can't answer that. Try asking in a different way.";
      if (code === "budget_exceeded") return "This assistant has reached its spending limit for now.";
      throw new Error(`AI Gateway refused the request: ${code} (reference ${requestId})`);
    }
  }
  ```
</CodeGroup>

With the Anthropic SDK the code is in `error.body["error"]["type"]`; with the Gemini SDK, in the error's `status`.

## Show people a helpful message

Guardrail messages name the guardrails that fired and never repeat the text that triggered them, so they are safe to log. They are written for the developer, not for the person using your application: show your own wording, as in the example.

## Keep the reference

Every reply, error or not, carries `x-request-id`. Log it with every error. Support and your admins can find the request in the [request log](/ai-gateway/request-logs) from it. To set your own reference, send `x-request-id` with the request.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.