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

# Error Codes

> Complete reference for all error codes returned by the API and SDK

## Overview

VIZOCHOK uses machine-readable error codes throughout the system. The backend sends structured error objects with a `code` field, and the SDK maps these codes to localized human-readable messages in the widget's configured language (Ukrainian or English).

The backend never sends user-facing text. It sends a code, and the client renders the appropriate message.

## WebSocket Error Codes

These errors are sent as `{"type": "error", "code": "..."}` messages over the WebSocket connection.

### Rate Limiting Errors

| Code                         | Description                                                                      | Retry | Additional Fields       |
| ---------------------------- | -------------------------------------------------------------------------------- | ----- | ----------------------- |
| `rate_limit_exceeded`        | Too many messages in the current window (10 per 60 seconds per connection).      | Yes   | `retry_after` (seconds) |
| `user_message_limit`         | User has reached the daily message limit (default: 200/day).                     | No    | `limit` (max count)     |
| `user_conversation_limit`    | User has reached the daily conversation limit (default: 20/day).                 | No    | `limit` (max count)     |
| `tenant_daily_token_limit`   | Tenant has exceeded the daily token budget (default: 500,000 tokens/day).        | No    | --                      |
| `tenant_monthly_token_limit` | Tenant has exceeded the monthly token budget (default: 10,000,000 tokens/month). | No    | --                      |

### Session Errors

| Code                  | Description                                                                                                                     | Retry |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ----- |
| `agent_busy`          | Another request is already being processed for this conversation. The agent uses a Redis lock to prevent concurrent processing. | Yes   |
| `session_token_limit` | The conversation has exceeded the per-session token limit. The user should start a new conversation.                            | No    |
| `max_rounds_exceeded` | The agent's tool chain exceeded the maximum number of iterations. The user should simplify their request.                       | No    |

### Input Errors

| Code                | Description                                                                     | Additional Fields  |
| ------------------- | ------------------------------------------------------------------------------- | ------------------ |
| `message_too_large` | Message exceeds the 64 KB size limit. Checked both client-side and server-side. | `max_size` (bytes) |
| `invalid_json`      | The message could not be parsed as valid JSON, or failed Pydantic validation.   | --                 |

### System Errors

| Code              | Description                                                                                           |
| ----------------- | ----------------------------------------------------------------------------------------------------- |
| `internal_error`  | An unexpected server error occurred. Also sent on agent processing timeout (120s).                    |
| `no_catalog_data` | The tenant's product catalog has no active products. Sent on the first message of a new conversation. |

## SDK Client-Side Error Codes

These errors are generated by the widget SDK itself (not from the server) and delivered through the `onError` callback.

| Code                | Description                                                                                   |
| ------------------- | --------------------------------------------------------------------------------------------- |
| `auth_timeout`      | The server did not respond with `auth_ok` within 10 seconds of the auth message.              |
| `auth_error`        | Authentication failed. The WebSocket was closed with a 4001-4004 close code.                  |
| `ws_error`          | WebSocket connection error (network failure, DNS resolution failure, etc.).                   |
| `message_too_large` | Client-side check: message exceeds 64 KB before sending (prevents unnecessary round-trip).    |
| `queue_full`        | The client-side message queue has reached its maximum capacity (50 messages).                 |
| `max_reconnect`     | Maximum reconnection attempts (30) exhausted without establishing a connection.               |
| `connection_lost`   | Connection was lost while the server was streaming a response. The partial text is preserved. |

## WebSocket Close Codes

When the server closes the WebSocket connection, it uses these custom close codes:

| Code   | Reason                                  | Description                                                                                                                      |
| ------ | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `4001` | Auth timeout / Invalid auth             | First message was not an auth message, auth timed out, or the message failed validation. Also used for invalid/expired API keys. |
| `4002` | API key lacks chat scope                | The API key is valid but does not have the `chat` scope.                                                                         |
| `4003` | Origin not allowed / Tenant deactivated | WebSocket origin is not in the allowed origins list, or the tenant account is deactivated.                                       |
| `4004` | Tenant LLM not configured               | The tenant exists but has no LLM provider configured.                                                                            |
| `4005` | Auth timeout (client)                   | Client-side auth timeout -- sent by the SDK if no `auth_ok` is received within 10 seconds.                                       |
| `4008` | Heartbeat timeout                       | No pong received within 60 seconds. The connection is considered dead.                                                           |
| `4029` | Too many connections                    | Exceeded the maximum concurrent WebSocket connections per API key (3).                                                           |

## REST API Error Responses

REST API endpoints (admin panel, catalog management) return standard HTTP error responses:

```json theme={null}
{
  "detail": "Human-readable error message"
}
```

### Common HTTP Status Codes

| Status | Usage                                                                          |
| ------ | ------------------------------------------------------------------------------ |
| `400`  | Invalid request body or parameters (e.g., invalid webhook URL).                |
| `401`  | Invalid or expired credentials (API key, JWT session).                         |
| `403`  | Insufficient permissions (e.g., non-owner trying to manage users).             |
| `404`  | Resource not found (tenant, user, API key).                                    |
| `409`  | Conflict (e.g., duplicate email, cannot deactivate yourself, last active key). |
| `422`  | Validation error (e.g., password too short, Pydantic validation failure).      |
| `429`  | Too many login attempts.                                                       |

## Error Localization

The SDK maintains built-in translations for all server error codes:

<CodeGroup>
  ```typescript English theme={null}
  {
    rate_limit_exceeded: 'Too many messages. Please wait a moment.',
    user_message_limit: 'Daily message limit reached.',
    user_conversation_limit: 'Daily conversation limit reached.',
    tenant_daily_token_limit: 'Service temporarily unavailable. Please try again later.',
    tenant_monthly_token_limit: 'Service temporarily unavailable. Please try again later.',
    agent_busy: 'Assistant is processing a previous request.',
    message_too_large: 'Message is too long. Please shorten it.',
    invalid_json: 'Message format error.',
    internal_error: 'Something went wrong. Please try again.',
    max_rounds_exceeded: 'Request was too complex. Please simplify your question.',
    session_token_limit: 'Conversation is too long. Please start a new one.',
    no_catalog_data: 'Product catalog is not loaded yet.',
  }
  ```

  ```typescript Ukrainian theme={null}
  {
    rate_limit_exceeded: 'Зачекайте, забагато повідомлень',
    user_message_limit: 'Ви досягли ліміту повідомлень на сьогодні',
    user_conversation_limit: 'Ви досягли ліміту розмов на сьогодні',
    tenant_daily_token_limit: 'Сервіс тимчасово недоступний',
    tenant_monthly_token_limit: 'Сервіс тимчасово недоступний',
    agent_busy: 'Зачекайте, обробляю попереднє повідомлення',
    message_too_large: 'Повідомлення занадто довге',
    invalid_json: 'Помилка відправки повідомлення',
    internal_error: 'Щось пішло не так, спробуйте ще раз',
    max_rounds_exceeded: 'Не вдалося обробити запит, спробуйте інакше',
    session_token_limit: 'Сесія досягла ліміту, почніть нову розмову',
    no_catalog_data: 'Каталог товарів ще не завантажено. Зверніться до адміністратора.',
  }
  ```
</CodeGroup>

<Note>
  Russian language (`'ru'`) uses the Ukrainian translations, since the AI always responds in Ukrainian for Russian-language input.
</Note>

## Error Handling Best Practices

### In the Widget

```typescript theme={null}
const widget = new VizochokWidget({
  apiKey: 'pk_your_key',
  storeId: 'your-store',

  onError: (error) => {
    switch (error.code) {
      // Auth errors -- cannot recover without config change
      case 'auth_error':
      case 'auth_timeout':
        console.error('Widget auth failed:', error.message);
        break;

      // Rate limits -- temporary, auto-recovers
      case 'rate_limit_exceeded':
      case 'user_message_limit':
        // Widget shows the error inline; no action needed
        break;

      // Tenant limits -- contact support
      case 'tenant_daily_token_limit':
      case 'tenant_monthly_token_limit':
        reportToAdmin('VIZOCHOK token limit reached');
        break;

      // Connection issues -- widget auto-reconnects
      case 'ws_error':
      case 'connection_lost':
        // No action needed
        break;

      // Fatal connection failure
      case 'max_reconnect':
        showFallback('Chat is temporarily unavailable');
        break;

      default:
        console.warn('VIZOCHOK error:', error.code, error.message);
    }
  },
});
```

### General Guidelines

1. **Do not suppress errors silently.** At minimum, log them for debugging.
2. **Tenant limit errors are your concern.** Monitor `tenant_daily_token_limit` and `tenant_monthly_token_limit` and upgrade your plan before hitting limits.
3. **The widget handles display.** All error codes are rendered as user-friendly messages inside the chat panel automatically. The `onError` callback is for your application logic, not for displaying errors to users.
4. **Connection errors auto-recover.** The SDK has built-in reconnection with exponential backoff (1s to 10s, up to 30 attempts). You do not need to implement your own reconnection logic.
5. **The `retry_after` field** on `rate_limit_exceeded` tells you how many seconds to wait. The widget displays a countdown timer automatically.
