> For the complete documentation index, see [llms.txt](https://docs.snackprompt.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.snackprompt.com/bring-your-data-into-ai/reference/error-codes.md).

# Error Codes

Complete list of error codes for the SnackPrompt AI Engine API.

### Overview

The API returns errors in the following format:

```json
{
  "detail": "Message describing the error"
}
```

### HTTP Codes

| Code | Name                  | Description                            |
| ---- | --------------------- | -------------------------------------- |
| 200  | OK                    | Successful request                     |
| 202  | Accepted              | Request accepted for processing        |
| 400  | Bad Request           | Validation error or invalid parameters |
| 401  | Unauthorized          | Not authenticated                      |
| 403  | Forbidden             | No permission to access resource       |
| 404  | Not Found             | Resource not found                     |
| 422  | Unprocessable Entity  | Invalid data                           |
| 429  | Too Many Requests     | Rate limit exceeded                    |
| 500  | Internal Server Error | Internal server error                  |
| 503  | Service Unavailable   | Service temporarily unavailable        |

***

### Common Errors

#### 400 - tenant\_id Required

**Response:**

```json
{
  "detail": "tenant_id is required in filters"
}
```

**Cause:** The `tenant_id` was not included in the `filters` object.

**Solution:** Add `tenant_id` to filters:

```json
{
  "query": "your search",
  "filters": {
    "tenant_id": "your-tenant-id"
  }
}
```

***

#### 400 - Query Required

**Response:**

```json
{
  "detail": "query is required"
}
```

**Cause:** The `query` field was not provided in a search or chat request.

**Solution:** Add the `query` field:

```json
{
  "query": "your question here",
  "filters": {
    "tenant_id": "..."
  }
}
```

***

#### 400 - Invalid Filters

**Response:**

```json
{
  "detail": "Invalid filter: unknown_field"
}
```

**Cause:** An unknown filter was provided.

**Solution:** Use only valid filters. See Filter Reference.

***

#### 404 - Elemental Not Found

**Response:**

```json
{
  "detail": "Elemental not found: elem-123"
}
```

**Cause:** The provided `elemental_id` doesn't exist or hasn't been ingested.

**Solution:**

1. Check if the ID is correct
2. Check if the elemental was ingested
3. Wait for ingestion to complete (asynchronous process)

***

#### 422 - Invalid Data

**Response:**

```json
{
  "detail": [
    {
      "loc": ["body", "filters", "limit"],
      "msg": "value is not a valid integer",
      "type": "type_error.integer"
    }
  ]
}
```

**Cause:** A field was provided with the wrong type.

**Solution:** Check data types. See Data Models.

***

#### 429 - Rate Limit

**Response:**

```json
{
  "detail": "Rate limit exceeded. Try again in 60 seconds."
}
```

**Cause:** Too many requests in a short period.

**Solution:**

1. Wait the indicated time
2. Implement retry with exponential backoff
3. Consider upgrading your plan for more requests

**Response headers:**

```
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1699999999
```

***

#### 500 - Internal Error

**Response:**

```json
{
  "detail": "Internal server error"
}
```

**Cause:** Unexpected server error.

**Solution:**

1. Try again in a few seconds
2. If it persists, contact support
3. Include the `trace_id` if available

***

#### 503 - Service Unavailable

**Response:**

```json
{
  "detail": "Service temporarily unavailable"
}
```

**Cause:** The service or a dependency is unavailable.

**Solution:**

1. Wait a few minutes
2. Check status at `/health/detailed`
3. Contact support if it persists

***

### Streaming Errors

#### Error During Streaming

During streaming chat, errors are sent as SSE events:

```
data: {"event":"error","data":{"message":"Error generating response"}}
```

**Solution:** Handle the `error` event in your client:

```javascript
eventSource.addEventListener('message', (event) => {
  const data = JSON.parse(event.data);
  if (data.event === 'error') {
    console.error('Stream error:', data.data.message);
  }
});
```

***

### Recommended Error Handling

#### JavaScript/TypeScript

```typescript
async function searchKnowledgeBase(query: string, tenantId: string) {
  try {
    const response = await fetch('https://api-integrations.snackprompt.com/v1/kb/search', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        query,
        filters: { tenant_id: tenantId }
      })
    });

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

      switch (response.status) {
        case 400:
          throw new Error(`Validation error: ${error.detail}`);
        case 404:
          throw new Error(`Not found: ${error.detail}`);
        case 429:
          throw new Error('Rate limit exceeded. Please wait.');
        default:
          throw new Error(`API error: ${error.detail}`);
      }
    }

    return await response.json();
  } catch (error) {
    console.error('Search failed:', error);
    throw error;
  }
}
```

#### Python

```python
import requests

def search_knowledge_base(query: str, tenant_id: str):
    try:
        response = requests.post(
            'https://api-integrations.snackprompt.com/v1/kb/search',
            json={
                'query': query,
                'filters': {'tenant_id': tenant_id}
            }
        )
        response.raise_for_status()
        return response.json()

    except requests.exceptions.HTTPError as e:
        if e.response.status_code == 400:
            raise ValueError(f"Validation error: {e.response.json()['detail']}")
        elif e.response.status_code == 429:
            raise Exception("Rate limit exceeded")
        else:
            raise Exception(f"API error: {e.response.json()['detail']}")
```

***

### Retry with Exponential Backoff

For 429 and 5xx errors, implement retry with backoff:

```python
import time
import random

def retry_with_backoff(func, max_retries=3):
    for attempt in range(max_retries):
        try:
            return func()
        except Exception as e:
            if attempt == max_retries - 1:
                raise

            wait_time = (2 ** attempt) + random.uniform(0, 1)
            print(f"Retry {attempt + 1}/{max_retries} in {wait_time:.1f}s")
            time.sleep(wait_time)
```
