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

# Error Handling

> Error response format and error codes for the Fanfare API

The Fanfare API uses conventional HTTP response codes to indicate the success or failure of an API request.

## Error Response Format

All error responses follow a consistent JSON structure:

```json theme={null}
{
  "error": "Error type or message",
  "message": "Human-readable description (optional)",
  "details": [
    {
      "field": "fieldName",
      "message": "Field-specific error message"
    }
  ]
}
```

## HTTP Status Codes

### Success Codes (2xx)

| Code             | Description                                 |
| ---------------- | ------------------------------------------- |
| `200 OK`         | The request succeeded                       |
| `201 Created`    | A new resource was created                  |
| `204 No Content` | The request succeeded with no response body |

### Client Error Codes (4xx)

| Code                    | Description                                                        |
| ----------------------- | ------------------------------------------------------------------ |
| `400 Bad Request`       | The request was malformed or contained invalid data                |
| `401 Unauthorized`      | Authentication credentials were missing or invalid                 |
| `403 Forbidden`         | The authenticated user lacks permission for the requested action   |
| `404 Not Found`         | The requested resource does not exist                              |
| `409 Conflict`          | The request conflicts with the current state of the resource       |
| `413 Payload Too Large` | The request body exceeds the maximum allowed size                  |
| `423 Locked`            | The resource is temporarily unavailable (e.g., queue not yet open) |
| `429 Too Many Requests` | Rate limit exceeded                                                |

### Server Error Codes (5xx)

| Code                        | Description                                |
| --------------------------- | ------------------------------------------ |
| `500 Internal Server Error` | An unexpected error occurred on the server |
| `503 Service Unavailable`   | The service is temporarily unavailable     |

## Common Error Types

### Authentication Errors

**Missing Authentication**

```http theme={null}
HTTP/1.1 401 Unauthorized
```

```json theme={null}
{
  "error": "Authentication required"
}
```

**Invalid Token**

```http theme={null}
HTTP/1.1 401 Unauthorized
```

```json theme={null}
{
  "error": "invalid refresh token"
}
```

**Secret Key Required**

```http theme={null}
HTTP/1.1 401 Unauthorized
```

```json theme={null}
{
  "error": "Secret key required"
}
```

### Validation Errors

**Field Validation Failed**

```http theme={null}
HTTP/1.1 400 Bad Request
```

```json theme={null}
{
  "error": "Validation failed",
  "details": [
    {
      "field": "email",
      "message": "Invalid email format"
    },
    {
      "field": "capacity",
      "message": "Must be a positive integer"
    }
  ]
}
```

**Missing Required Field**

```http theme={null}
HTTP/1.1 400 Bad Request
```

```json theme={null}
{
  "error": "Validation failed",
  "details": [
    {
      "field": "name",
      "message": "Required"
    }
  ]
}
```

**Database Constraint Violation**

```http theme={null}
HTTP/1.1 400 Bad Request
```

```json theme={null}
{
  "error": "Validation failed",
  "details": [
    {
      "field": "slug",
      "message": "Already taken"
    }
  ]
}
```

### Resource Errors

**Resource Not Found**

```http theme={null}
HTTP/1.1 404 Not Found
```

```json theme={null}
{
  "error": "Experience not found"
}
```

**Resource Conflict**

```http theme={null}
HTTP/1.1 409 Conflict
```

```json theme={null}
{
  "error": "Sync already in progress"
}
```

### State Errors

**Queue Not Open**

```http theme={null}
HTTP/1.1 423 Locked
Retry-After: 2024-12-01T09:00:00Z
```

```json theme={null}
{
  "error": "Queue is not open yet"
}
```

**Queue Full**

```http theme={null}
HTTP/1.1 429 Too Many Requests
Retry-After: 30
```

```json theme={null}
{
  "error": "Queue is full"
}
```

**Auction Closed**

```http theme={null}
HTTP/1.1 400 Bad Request
```

```json theme={null}
{
  "error": "Auction is closed"
}
```

### OTP Errors

**OTP Expired**

```http theme={null}
HTTP/1.1 401 Unauthorized
```

```json theme={null}
{
  "error": "otp_expired",
  "message": "Your verification code has expired. Please request a new one."
}
```

**Invalid OTP**

```http theme={null}
HTTP/1.1 401 Unauthorized
```

```json theme={null}
{
  "error": "otp_invalid",
  "message": "Invalid verification code. Please try again."
}
```

### Session Integrity Errors

Some endpoints may require additional session integrity checks before a consumer can continue:

```http theme={null}
HTTP/1.1 403 Forbidden
```

```json theme={null}
{
  "error": "session_integrity_failed",
  "message": "This action could not be completed. Please refresh the page and try again.",
  "support": {
    "message": "If the issue continues, contact support with this reference code.",
    "referenceCode": "ABC123XYZ"
  }
}
```

### Rate Limiting Errors

```http theme={null}
HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1701424860
```

```json theme={null}
{
  "error": "Rate limit exceeded",
  "retryAfter": 60
}
```

### Order Limit Errors

When a consumer exceeds purchase limits:

```json theme={null}
{
  "status": "DENIED",
  "denyReason": "ORDER_LIMIT_EXCEEDED",
  "consumerId": "cons_01HXYZ123456789"
}
```

## Error Handling Best Practices

### 1. Check HTTP Status Code First

```javascript theme={null}
const response = await fetch(url, options);

if (!response.ok) {
  const error = await response.json();
  // Handle based on status code
  switch (response.status) {
    case 400:
      handleValidationError(error);
      break;
    case 401:
      handleAuthError(error);
      break;
    case 429:
      handleRateLimitError(error, response.headers);
      break;
    default:
      handleGenericError(error);
  }
}
```

### 2. Respect Retry-After Headers

```javascript theme={null}
if (response.status === 429 || response.status === 423) {
  const retryAfter = response.headers.get("Retry-After");
  if (retryAfter) {
    // Could be seconds or ISO timestamp
    const delay = isNaN(retryAfter) ? new Date(retryAfter).getTime() - Date.now() : parseInt(retryAfter) * 1000;
    await sleep(delay);
    // Retry the request
  }
}
```

### 3. Display User-Friendly Messages

Map error codes to user-friendly messages:

```javascript theme={null}
const errorMessages = {
  otp_expired: "Your code has expired. Please request a new one.",
  otp_invalid: "That code doesn't look right. Please check and try again.",
  session_integrity_failed: "Please refresh the page and try again.",
  "Queue is full": "Sorry, this queue is currently full. Please try again later.",
};
```

### 4. Log Errors for Debugging

Include relevant context in error logs:

```javascript theme={null}
console.error("API Error", {
  status: response.status,
  error: error.error,
  details: error.details,
  requestId: response.headers.get("X-Request-Id"),
  timestamp: new Date().toISOString(),
});
```

## Error Recovery Strategies

### Transient Errors (5xx)

Implement exponential backoff:

```javascript theme={null}
async function retryWithBackoff(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      if (error.status >= 500) {
        await sleep(Math.pow(2, i) * 1000);
      } else {
        throw error; // Don't retry client errors
      }
    }
  }
}
```

### Token Expiration

Automatically refresh tokens when expired:

```javascript theme={null}
async function apiCall(url, options) {
  const response = await fetch(url, options);

  if (response.status === 401) {
    const refreshed = await refreshToken();
    if (refreshed) {
      // Retry with new token
      return fetch(url, {
        ...options,
        headers: {
          ...options.headers,
          Authorization: `Bearer ${refreshed.accessToken}`,
        },
      });
    }
  }

  return response;
}
```
