Документация

Ошибки

API LLMost использует стандартные коды состояния HTTP для указания на успех или неудачу запроса. В случае ошибки вы получите структурированный ответ с подробной информацией о проблеме.

Структура ответа об ошибке

Все ошибки возвращаются в следующем формате:

type ErrorResponse = {
  error: {
    code: number;        // HTTP код состояния
    message: string;     // Описание ошибки
    metadata?: Record<string, unknown>;  // Дополнительная информация об ошибке
  }
};

Пример ответа об ошибке

{
  "error": {
    "code": 401,
    "message": "Неверные учетные данные",
    "metadata": {
      "reason": "invalid_api_key"
    }
  }
}

Коды ошибок HTTP

400 - Неверный запрос

Запрос содержит недопустимые параметры или неправильно сформирован.

Возможные причины:

  • Отсутствуют обязательные параметры
  • Неверный формат данных
  • Проблемы с CORS (при запросах из браузера)
  • Недопустимые значения параметров
{
  "error": {
    "code": 400,
    "message": "Параметр 'model' является обязательным",
    "metadata": {
      "parameter": "model",
      "provided": null
    }
  }
}

Совет по отладке

При получении ошибки 400, проверьте:

  • Все обязательные параметры присутствуют
  • Форматирование JSON корректно
  • Значения параметров находятся в допустимых диапазонах
  • Заголовки Content-Type установлены правильно

401 - Неавторизован

Проблема с аутентификацией. API-ключ отсутствует, недействителен или истек.

Возможные причины:

  • API-ключ не предоставлен
  • API-ключ недействителен
  • API-ключ был отозван
  • Неправильный формат заголовка Authorization
{
  "error": {
    "code": 401,
    "message": "Неверные учетные данные",
    "metadata": {
      "reason": "invalid_api_key"
    }
  }
}

Решение:

  1. Проверьте, что API-ключ правильно установлен в заголовке Authorization: Bearer ВАШ_КЛЮЧ
  2. Создайте новый API-ключ на странице ключей
  3. Убедитесь, что в ключе нет лишних пробелов или символов

402 - Требуется оплата

Недостаточно кредитов на аккаунте для выполнения запроса.

{
  "error": {
    "code": 402,
    "message": "Недостаточно кредитов на аккаунте",
    "metadata": {
      "balance": 0.00
    }
  }
}

Решение:

  1. Пополните баланс на странице биллинга
  2. Проверьте лимиты расходов вашего API-ключа

403 - Запрещено

Запрос был заблокирован системой модерации или по другим причинам безопасности.

Ошибки модерации

Когда контент нарушает политику использования модели или провайдера:

{
  "error": {
    "code": 403,
    "message": "Ваш запрос был отклонен в результате модерации нашей системы безопасности",
    "metadata": {
      "reasons": ["Обнаружен потенциально вредный контент"],
      "flagged_input": "...",
      "provider": "openai",
      "model": "gpt-4"
    }
  }
}

Поля метаданных:

  • reasons - Причины блокировки контента
  • flagged_input - Фрагмент заблокированного ввода
  • provider - Провайдер модели
  • model - Идентификатор модели

Политика модерации

Разные модели и провайдеры имеют разные политики модерации. Контент, заблокированный одной моделью, может быть принят другой.

408 - Истекло время ожидания

Запрос превысил максимально допустимое время выполнения.

{
  "error": {
    "code": 408,
    "message": "Время ожидания запроса истекло",
    "metadata": {
      "timeout": "120s",
      "elapsed": "125s"
    }
  }
}

Решение:

  1. Попробуйте уменьшить max_tokens
  2. Упростите запрос
  3. Попробуйте другую модель
  4. Повторите запрос через некоторое время

429 - Слишком много запросов

Превышен лимит частоты запросов.

{
  "error": {
    "code": 429,
    "message": "Превышен лимит частоты запросов",
    "metadata": {
      "retry_after": 60,
      "limit": "100 requests per minute",
      "reset_at": "2025-01-15T12:35:00Z"
    }
  }
}

Решение:

  1. Внедрите экспоненциальную задержку при повторных попытках
  2. Проверьте поле retry_after для оптимального времени повтора
  3. Рассмотрите возможность кэширования ответов
  4. Распределите запросы равномерно во времени

Рекомендации по повторным попыткам

async function retryWithBackoff(fn: () => Promise<any>, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error: any) {
      if (error.error?.code === 429) {
        const delay = error.error.metadata?.retry_after ? error.error.metadata.retry_after * 1000 : Math.pow(2, i) * 1000;
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      throw error;
    }
  }
  throw new Error('Превышено максимальное количество повторных попыток');
}

502 - Модель недоступна

Запрошенная модель временно недоступна.

{
  "error": {
    "code": 502,
    "message": "Модель временно недоступна",
    "metadata": {
      "model": "openai/gpt-4o",
      "provider": "openai",
      "status": "down"
    }
  }
}

Решение:

  1. Попробуйте другую модель того же провайдера
  2. Попробуйте аналогичную модель от другого провайдера
  3. Повторите запрос через несколько минут
  4. Проверьте страницу статуса для информации о работоспособности

503 - Нет доступных провайдеров

Ни один провайдер не может обработать запрос в данный момент.

{
  "error": {
    "code": 503,
    "message": "Нет доступных провайдеров модели",
    "metadata": {
      "model": "openai/gpt-4o",
      "attempted_providers": ["openai", "azure"]
    }
  }
}

Решение:

  1. Подождите несколько минут и повторите попытку
  2. Попробуйте альтернативную модель
  3. Проверьте статус сервиса

Обработка ошибок при потоковой передаче

При использовании stream: true, ошибки обрабатываются по-разному в зависимости от того, когда они возникают.

Ошибки до начала потока

Если ошибка возникает до начала потоковой передачи, возвращается стандартный JSON с ошибкой:

{
  "error": {
    "code": 400,
    "message": "Неверный параметр model"
  }
}

Ошибки во время потока

Если ошибка возникает во время потоковой передачи, она отправляется как событие Server-Sent Event (SSE):

// HTTP статус остается 200 OK
data: {
  "id": "gen-xxxxx",
  "choices": [{
    "delta": { "content": "" },
    "finish_reason": "error",
    "error": {
      "code": 500,
      "message": "Ошибка провайдера во время генерации",
      "metadata": {
        "provider": "anthropic",
        "raw_error": "Connection reset by peer"
      }
    }
  }]
}

Важно: HTTP-статус будет 200 OK, даже если произошла ошибка во время потока. Всегда проверяйте поле error в каждом чанке.

Пример обработки потоковых ошибок

const response = await fetch('https://llmost.ru/api/v1/chat/completions', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer ВАШ_API_КЛЮЧ',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'openai/gpt-4o',
    messages: [{ role: 'user', content: 'Привет!' }],
    stream: true,
  }),
});

const reader = response.body?.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader!.read();
  if (done) break;

  const chunk = decoder.decode(value);
  const lines = chunk.split('\n').filter(line => line.trim().startsWith('data:'));

  for (const line of lines) {
    const data = line.replace('data: ', '');
    if (data === '[DONE]') continue;

    try {
      const parsed = JSON.parse(data);

      // Проверка на ошибки в потоке
      if (parsed.choices?.[0]?.error) {
        const error = parsed.choices[0].error;
        console.error('Ошибка во время потока:', error.message);
        // Обработка ошибки
        break;
      }

      // Обработка контента
      const content = parsed.choices?.[0]?.delta?.content;
      if (content) {
        process.stdout.write(content);
      }
    } catch (e) {
      console.error('Ошибка парсинга SSE:', e);
    }
  }
}

Ошибки провайдеров

Когда ошибка происходит на стороне провайдера модели, метаданные включают дополнительную информацию:

{
  "error": {
    "code": 500,
    "message": "Ошибка провайдера",
    "metadata": {
      "provider": "anthropic",
      "provider_error": {
        "type": "overloaded_error",
        "message": "Сервис перегружен, попробуйте позже"
      },
      "raw_response": "..."
    }
  }
}

Поля метаданных провайдера:

  • provider - Имя провайдера (openai, anthropic, google и т.д.)
  • provider_error - Структурированная ошибка от провайдера
  • raw_response - Необработанный ответ провайдера (если доступен)

Лучшие практики обработки ошибок

1. Всегда проверяйте статус ответа

const response = await fetch('https://llmost.ru/api/v1/chat/completions', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer ВАШ_API_КЛЮЧ',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ /* ... */ }),
});

if (!response.ok) {
  const error = await response.json();
  throw new Error(`API Error ${error.error.code}: ${error.error.message}`);
}

const data = await response.json();

2. Обрабатывайте разные типы ошибок

try {
  const completion = await generateCompletion(prompt);
  return completion;
} catch (error: any) {
  const code = error.error?.code;

  switch (code) {
    case 401:
      // Проблема с аутентификацией
      console.error('Проверьте ваш API-ключ');
      break;

    case 402:
      // Недостаточно средств
      console.error('Пополните баланс аккаунта');
      break;

    case 429:
      // Rate limit
      const retryAfter = error.error?.metadata?.retry_after || 60;
      console.log(`Повтор через ${retryAfter} секунд`);
      await sleep(retryAfter * 1000);
      return generateCompletion(prompt); // Retry

    case 502:
    case 503:
      // Временные проблемы с сервисом
      console.log('Попробуйте альтернативную модель');
      break;

    default:
      console.error('Неожиданная ошибка:', error.error?.message);
  }

  throw error;
}

3. Логируйте метаданные ошибок

Метаданные содержат ценную информацию для отладки:

try {
  const result = await apiCall();
} catch (error: any) {
  console.error('API Error:', {
    code: error.error?.code,
    message: error.error?.message,
    metadata: error.error?.metadata,
    timestamp: new Date().toISOString(),
  });

  // Отправка в систему мониторинга
  monitoringService.logError(error);
}

4. Используйте повторные попытки с задержкой

async function callWithRetry<T>(
  fn: () => Promise<T>,
  options = { maxRetries: 3, baseDelay: 1000 }
): Promise<T> {
  let lastError: any;

  for (let attempt = 0; attempt < options.maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error: any) {
      lastError = error;
      const code = error.error?.code;

      // Не повторяем для определенных ошибок
      if ([400, 401, 403].includes(code)) {
        throw error;
      }

      // Экспоненциальная задержка
      const delay = options.baseDelay * Math.pow(2, attempt);
      console.log(`Попытка ${attempt + 1} не удалась, повтор через ${delay}мс`);
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }

  throw lastError;
}

// Использование
const completion = await callWithRetry(() =>
  fetch('https://llmost.ru/api/v1/chat/completions', {
    method: 'POST',
    headers: { /* ... */ },
    body: JSON.stringify({ /* ... */ }),
  }).then(r => r.json())
);

5. Graceful degradation

Имейте запасные варианты на случай сбоев:

async function generateWithFallback(prompt: string) {
  const models = [
    'openai/gpt-4o',
    'anthropic/claude-3.5-sonnet',
    'google/gemini-pro',
  ];

  for (const model of models) {
    try {
      return await generate(prompt, model);
    } catch (error: any) {
      console.warn(`Модель ${model} не удалась:`, error.error?.message);
      // Пробуем следующую модель
      continue;
    }
  }

  throw new Error('Все модели недоступны');
}

Типы TypeScript

// Для строгой типизации ошибок
interface LLMostError {
  error: {
    code: number;
    message: string;
    metadata?: {
      // Метаданные модерации
      reasons?: string[];
      flagged_input?: string;
      provider?: string;
      model?: string;

      // Метаданные rate limit
      retry_after?: number;
      limit?: string;
      reset_at?: string;

      // Метаданные провайдера
      provider_error?: {
        type: string;
        message: string;
      };
      raw_response?: string;

      // Общие метаданные
      [key: string]: unknown;
    };
  };
}

// Защита типов
function isLLMostError(error: unknown): error is LLMostError {
  return (
    typeof error === 'object' &&
    error !== null &&
    'error' in error &&
    typeof (error as any).error?.code === 'number'
  );
}

// Использование
try {
  const response = await fetch(/* ... */);
  const data = await response.json();

  if (isLLMostError(data)) {
    // TypeScript теперь знает структуру ошибки
    console.error(`Код ошибки: ${data.error.code}`);
    console.error(`Сообщение: ${data.error.message}`);

    if (data.error.metadata?.retry_after) {
      console.log(`Повтор через: ${data.error.metadata.retry_after}с`);
    }
  }
} catch (e) {
  // Обработка сетевых ошибок
}

Следующие шаги

Ошибки | Документация | LLMost