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

# Errors

> Understand HTTP status codes, the JSON error response format, and how to handle common API errors

# Errors

The API uses standard HTTP status codes and returns a consistent JSON error format.

## Error response format

All error responses follow this structure:

```json theme={null}
{
  "success": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "Equipment not found"
  }
}
```

| Field           | Type    | Description                 |
| --------------- | ------- | --------------------------- |
| `success`       | `false` | Always `false` for errors   |
| `error.code`    | string  | Machine-readable error code |
| `error.message` | string  | Human-readable description  |

## Status codes

| Status | Code             | Meaning                                                 |
| ------ | ---------------- | ------------------------------------------------------- |
| `400`  | `BAD_REQUEST`    | Invalid request parameters or body                      |
| `401`  | `UNAUTHORIZED`   | Missing or invalid API key                              |
| `403`  | `FORBIDDEN`      | Valid key but insufficient scopes                       |
| `404`  | `NOT_FOUND`      | Resource doesn't exist or isn't accessible              |
| `429`  | `RATE_LIMITED`   | Too many requests — see [Rate Limiting](/docs/rate-limiting) |
| `500`  | `INTERNAL_ERROR` | Unexpected server error                                 |

<Note>
  For security, requesting a resource that exists but belongs to another organization returns `404` (not `403`). This prevents ID enumeration attacks.
</Note>

## Handling errors

<CodeGroup>
  ```javascript Node.js theme={null}
  const response = await fetch('https://api.dronelist.io/v1/equipment/eq_abc123', {
    headers: { 'X-API-Key': 'dl_your_key_here' }
  });

  if (!response.ok) {
    const error = await response.json();

    switch (response.status) {
      case 401:
        // Invalid or expired API key
        throw new Error('Authentication failed');
      case 403:
        // Key lacks required scope
        throw new Error(`Insufficient permissions: ${error.error.message}`);
      case 404:
        // Resource not found
        return null;
      case 429:
        // Rate limited — retry after reset
        const resetAt = Number(response.headers.get('X-RateLimit-Reset'));
        // ... wait and retry
        break;
      default:
        throw new Error(`API error: ${error.error.message}`);
    }
  }

  const data = await response.json();
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      'https://api.dronelist.io/v1/equipment/eq_abc123',
      headers={'X-API-Key': 'dl_your_key_here'}
  )

  if response.status_code == 200:
      data = response.json()
  elif response.status_code == 401:
      raise Exception('Authentication failed')
  elif response.status_code == 404:
      data = None
  elif response.status_code == 429:
      # Rate limited — check X-RateLimit-Reset header
      pass
  else:
      error = response.json()
      raise Exception(f"API error: {error['error']['message']}")
  ```
</CodeGroup>

## Tips

* **Always check `success`** in the response body, not just the HTTP status
* **Log the full error response** in production for debugging
* **Implement retries** for `429` and `5xx` errors with exponential backoff
* **Don't retry** `400`, `401`, `403`, or `404` errors — they require code or configuration changes
