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

# Error Handling

> Handle API errors gracefully

## Error Response Format

All errors follow a consistent format:

```json theme={null}
{
  "success": false,
  "error": {
    "code": "error_code",
    "message": "Human-readable description",
    "details": {}  // Optional additional context
  }
}
```

## HTTP Status Codes

| Status | Meaning      | Action                        |
| ------ | ------------ | ----------------------------- |
| `400`  | Bad Request  | Check request body/parameters |
| `401`  | Unauthorized | Check API key                 |
| `403`  | Forbidden    | Check permissions/licenses    |
| `404`  | Not Found    | Check resource ID             |
| `429`  | Rate Limited | Wait and retry                |
| `500`  | Server Error | Retry with backoff            |

## Common Errors

### Authentication Errors (401)

```json theme={null}
{
  "success": false,
  "error": {
    "code": "unauthorized",
    "message": "Invalid or missing API key"
  }
}
```

**Solutions:**

* Ensure `X-Api-Key` header is present
* Check the key hasn't been revoked
* Verify the key format (`pk_live_...`)

### License Errors (403)

```json theme={null}
{
  "success": false,
  "error": {
    "code": "not_licensed",
    "message": "No active license for persona",
    "details": {
      "persona_id": "persona-abc..."
    }
  }
}
```

**Solutions:**

* Check your licensed personas with `GET /personas`
* Contact support to license additional personas

### Validation Errors (400)

```json theme={null}
{
  "success": false,
  "error": {
    "code": "invalid_request",
    "message": "Content must be between 10 and 500 characters",
    "details": {
      "field": "content",
      "constraint": "length"
    }
  }
}
```

**Solutions:**

* Check request body matches schema
* Ensure required fields are present
* Validate content length limits

### Rate Limit Errors (429)

```json theme={null}
{
  "success": false,
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded",
    "details": {
      "retry_after": 3600,
      "limit": 1000,
      "remaining": 0
    }
  }
}
```

**Solutions:**

* Wait for `retry_after` seconds
* Implement request queuing
* Contact support for higher limits

## Error Handling Patterns

### Basic Error Handler

```javascript theme={null}
async function apiRequest(path, options = {}) {
  const response = await fetch(`${BASE_URL}${path}`, {
    ...options,
    headers: {
      'X-Api-Key': API_KEY,
      'Content-Type': 'application/json',
      ...options.headers
    }
  });
  
  const data = await response.json();
  
  if (!response.ok) {
    throw new UnleeshedError(
      data.error.code,
      data.error.message,
      response.status,
      data.error.details
    );
  }
  
  return data;
}

class UnleeshedError extends Error {
  constructor(code, message, status, details = {}) {
    super(message);
    this.code = code;
    this.status = status;
    this.details = details;
  }
}
```

### Retry with Exponential Backoff

```javascript theme={null}
async function requestWithRetry(path, options = {}, maxRetries = 3) {
  let lastError;
  
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await apiRequest(path, options);
    } catch (error) {
      lastError = error;
      
      // Don't retry client errors (except rate limits)
      if (error.status >= 400 && error.status < 500 && error.status !== 429) {
        throw error;
      }
      
      // Calculate backoff delay
      const delay = error.status === 429
        ? (error.details.retry_after || 60) * 1000
        : Math.min(1000 * Math.pow(2, attempt), 30000);
      
      console.log(`Retry ${attempt + 1}/${maxRetries} in ${delay}ms`);
      await new Promise(r => setTimeout(r, delay));
    }
  }
  
  throw lastError;
}
```

### Graceful Degradation

```javascript theme={null}
async function getCommentariesSafely(topicId) {
  try {
    const result = await getTopicWithCommentaries(topicId);
    return {
      success: true,
      data: result.commentaries
    };
  } catch (error) {
    console.error('Failed to fetch commentaries:', error);
    
    // Return partial data or fallback
    if (error.code === 'rate_limit_exceeded') {
      return {
        success: false,
        error: 'Please try again in a few minutes',
        retryAfter: error.details.retry_after
      };
    }
    
    if (error.code === 'not_found') {
      return {
        success: false,
        error: 'Commentary not found'
      };
    }
    
    // Generic fallback
    return {
      success: false,
      error: 'Unable to load commentary. Please try again.'
    };
  }
}
```

## User-Facing Error Messages

Map error codes to user-friendly messages:

```javascript theme={null}
const ERROR_MESSAGES = {
  unauthorized: 'Authentication failed. Please contact support.',
  not_licensed: 'This content is not available.',
  rate_limit_exceeded: 'Too many requests. Please wait a moment.',
  invalid_request: 'Invalid request. Please check your input.',
  not_found: 'Content not found.',
  internal_error: 'Something went wrong. Please try again.',
};

function getUserMessage(error) {
  return ERROR_MESSAGES[error.code] || ERROR_MESSAGES.internal_error;
}
```

## Monitoring & Alerting

Track errors in your integration:

```javascript theme={null}
async function trackError(error, context = {}) {
  // Log to your monitoring service (e.g., Sentry, DataDog)
  console.error({
    service: 'unleeshed',
    code: error.code,
    message: error.message,
    status: error.status,
    ...context
  });
  
  // Alert on critical errors
  if (error.status >= 500 || error.code === 'unauthorized') {
    await alertTeam({
      severity: 'high',
      message: `Unleeshed API Error: ${error.code}`,
      details: error
    });
  }
}
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Rate Limits" icon="gauge" href="/resources/rate-limits">
    Understand API rate limits.
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/introduction">
    Complete API documentation.
  </Card>
</CardGroup>
