# Error Handling

> Understand the gateway's error response format, error types, HTTP status codes, and how to identify requests using gateway headers.

Canonical: https://ai-gateway.sassmaker.com/docs/error-handling

## Error Response Format

All errors from the gateway follow a consistent envelope compatible with the OpenAI client libraries:

```json
{
  "error": {
    "message": "Invalid authentication credentials.",
    "type": "authentication_error",
    "code": "invalid_api_key"
  }
}
```

### Fields

| Field | Type | Description |
|-------|------|-------------|
| `error.message` | string | Human-readable description of what went wrong |
| `error.type` | string | Machine-readable error category (see below) |
| `error.code` | string \| null | Optional fine-grained error code within the type |

## Error Types

| Type | HTTP Status | Description |
|------|-------------|-------------|
| `invalid_request_error` | `400` | The request body is malformed, missing required fields, or contains invalid values |
| `authentication_error` | `401` | The Bearer token is missing, invalid, or has been revoked |
| `rate_limit_error` | `429` | The request was rejected due to IP or provider rate limits |
| `provider_error` | `502` | The upstream provider returned an error or an unexpected response |
| `not_found_error` | `404` | The requested endpoint or resource does not exist |
| `service_unavailable` | `503` | No healthy provider is available to serve the requested model |

## Gateway Request ID

Every response — including errors — includes the header:

```
x-gateway-request-id: req_01j9xkz3p4q5r6s7t8u9v0w1
```

Include this ID when reporting issues. It uniquely identifies the request in the gateway's logs.

## Common Error Scenarios

### Missing or invalid token

```json
{
  "error": {
    "message": "Invalid authentication credentials.",
    "type": "authentication_error",
    "code": "invalid_api_key"
  }
}
```

**Fix:** Ensure your `Authorization` header is set to `Bearer <your-token>` and the token has not been revoked.

### Unsupported model

```json
{
  "error": {
    "message": "Model 'gpt-99' is not supported by this gateway.",
    "type": "not_found_error",
    "code": null
  }
}
```

**Fix:** Check the [Health](https://ai-gateway.sassmaker.com/health) endpoint for the list of currently configured models.

### Provider failure

```json
{
  "error": {
    "message": "The upstream provider returned an error: upstream connect error or disconnect/reset before headers.",
    "type": "provider_error",
    "code": null
  }
}
```

**Fix:** Retry with exponential backoff. The gateway will have already attempted its configured retry count before surfacing this error. Check [Health](https://ai-gateway.sassmaker.com/health) for provider status.

### All providers in cooldown

```json
{
  "error": {
    "message": "No healthy provider available for model 'llama-3.3-70b-versatile'. Please try again shortly.",
    "type": "service_unavailable",
    "code": null
  }
}
```

**Fix:** Wait for providers to exit cooldown (typically seconds to minutes) and retry.

## Handling Errors in Code


  
### curl

```bash
RESPONSE=$(curl -s -w "\n%{http_code}" \
  https://your-gateway.workers.dev/v1/chat/completions \
  -H "Authorization: Bearer <your-token>" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o","messages":[{"role":"user","content":"Hello"}]}')

HTTP_STATUS=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | head -n -1)

if [ "$HTTP_STATUS" -ne 200 ]; then
  echo "Error $HTTP_STATUS: $(echo "$BODY" | jq -r '.error.message')"
fi
```
  
  
### JavaScript

```js
async function chat(messages) {
  const response = await fetch(
    'https://your-gateway.workers.dev/v1/chat/completions',
    {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer <your-token>',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ model: 'gpt-4o', messages }),
    }
  );

  const requestId = response.headers.get('x-gateway-request-id');

  if (!response.ok) {
    const { error } = await response.json();
    throw Object.assign(
      new Error(error.message),
      { type: error.type, code: error.code, requestId }
    );
  }

  return response.json();
}

try {
  const result = await chat([{ role: 'user', content: 'Hello' }]);
  console.log(result);
} catch (err) {
  console.error(`[${err.type}] ${err.message} (request: ${err.requestId})`);

  if (err.type === 'rate_limit_error') {
    // inspect Retry-After header and back off
  }
}
```
