Ошибка 429 в OpenRouter не обязательно означает, что вы исчерпали лимит своего аккаунта. Запрос мог отклонить и выбранный внешний провайдер. Прежде чем менять ключ, покупать кредиты или добавлять ретраи, сохраните полный ответ с ошибкой: HTTP-статус, заголовки и JSON-тело покажут, какой именно лимит сработал.
Сначала разберите один ответ 429
Не пытайтесь исправлять проблему наугад. Структурированные поля OpenRouter и заголовки ответа надёжнее текста ошибки: в сообщении может оказаться формулировка, которую OpenRouter просто передал от внешнего провайдера.
| Признак | Наиболее вероятная причина | Что делать |
|---|---|---|
HTTP 429 и заголовки X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset | Лимит платформы OpenRouter | Дождаться сброса и уменьшить частоту запросов или параллелизм |
error.metadata.error_type имеет значение rate_limit_exceeded, а в деталях есть данные провайдера, например provider_code | Внешний провайдер | Подождать, разрешить другого провайдера или использовать резервную модель |
Присутствует Retry-After | Все опрошенные провайдеры указали время ожидания | Выдержать этот интервал перед следующей попыткой |
| HTTP 402 | Недостаточный баланс или исчерпан кредитный лимит ключа | Пополнить баланс или изменить лимит ключа: ретраи с задержкой не помогут |
HTTP 200, после которого приходит ошибка SSE и finish_reason: "error" | Сбой произошёл уже после начала стриминга | Считать поток неуспешным и проверить встроенный тип ошибки |
В справочнике OpenRouter по ошибкам и отладке описан контейнер с полями error.code, error.message и необязательным error.metadata, включая error_type = "rate_limit_exceeded". Там же указано, что успешные ответы обычно не содержат X-RateLimit-*. Перегрузка провайдера выделена в отдельный тип provider_overloaded и обычно соответствует статусу 503.
Что делать при 429 со стороны OpenRouter
429 на уровне OpenRouter связан с квотой платформы, зависящей от аккаунта и класса модели. Согласно официальной документации по лимитам, проверенной 31 июля 2026 года, у бесплатных вариантов моделей с суффиксом :free действуют поминутные и суточные ограничения.
| Квота бесплатных моделей | Текущий лимит |
|---|---|
| Запросов в минуту | 20 RPM |
| Запросов в сутки при суммарных покупках кредитов менее $10 | 50 RPD |
| Запросов в сутки при суммарных покупках кредитов от $10 | 1,000 RPD |
В политике лимитов прямо сказано: дополнительные аккаунты и ключи не увеличивают общую доступную ёмкость. Поэтому замена рабочего ключа не сбросит лимит платформы.
Проверить использование и кредитные ограничения можно через эндпоинт GET /api/v1/key:
curl https://openrouter.ai/api/v1/key \
-H "Authorization: Bearer $OPENROUTER_API_KEY"
Если 429 вернул сам OpenRouter, ориентируйтесь на заголовок сброса лимита и действуйте в таком порядке:
- Не повторяйте запрос сразу: дождитесь времени из
X-RateLimit-Reset. - Сократите число одновременных запросов, а не только запросов в секунду. Всплеск от параллельных воркеров может превысить лимит ещё до того, как первый из них увидит 429.
- Поставьте задачи в очередь за общим ограничителем, чтобы все воркеры не просыпались и не повторяли запросы одновременно.
- Если задача не укладывается в квоту бесплатной модели, перенесите этот трафик на подходящий платный вариант модели.
Отрицательный баланс или исчерпанный кредитный лимит ключа должны возвращать 402. При этом внешний провайдер вполне может отдать 429 и для аккаунта с пополненным балансом. В гайде по ценам OpenRouter отдельно разобраны вопросы стоимости и кредитов.
Как исправить 429 «Provider Returned Error»
429 с ошибкой от провайдера означает, что OpenRouter отправил запрос внешнему провайдеру инференса, но тот временно не смог его принять. Ищите типизированное значение лимита и метаданные провайдера: покупка кредитов OpenRouter не добавит мощности конкретному провайдеру.
В официальном справочнике лимитов сказано, что до возврата ошибки маршрутизация могла уже попробовать альтернативных провайдеров. Если подсказку об ожидании передали все опрошенные провайдеры, OpenRouter добавляет Retry-After. На практике стоит сделать следующее:
- Соблюдать
Retry-After, а не немедленно запускать генерацию того же запроса заново. - Убрать чрезмерно жёсткие ограничения на провайдеров, если из-за них остаётся лишь один перегруженный маршрут.
- Проверить, разрешён ли для запроса резервный провайдер.
- Настроить резервную модель, если завершение задачи важнее использования строго определённой модели.
Один пользователь Zed с пополненным аккаунтом столкнулся с лимитом внешнего провайдера для moonshotai/kimi-k2:free; создание нового ключа не помогло. Участник команды Zed пояснил:
«Это не ошибка Zed: OpenRouter сообщает, что используемый вами внешний провайдер ограничивает вас по частоте запросов». Источник: zed-industries/zed issue #35153
Если Retry-After короткий, просто подождите. Используйте резервную бесплатную модель только в случае, когда важнее завершить задачу, чем сохранить конкретную модель.
Если ошибка возникает в Janitor AI, Zed или SillyTavern
Сохраните исходный текст ошибки, не запускайте генерацию повторно много раз подряд и при сбоях на стороне провайдера смените модель или разрешённый маршрут. Вводить ключ заново имеет смысл только для исправления его хранения в клиенте — доступную ёмкость это не сбросит.
Ретраи без бесконечного цикла 429
Повторяйте только запросы, упавшие из-за ограничения частоты, ограничивайте число попыток и в первую очередь соблюдайте паузу, указанную сервером. Если подсказки нет, используйте экспоненциальную задержку с верхним пределом и случайным разбросом, чтобы параллельные клиенты не синхронизировались в новый всплеск запросов.
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
function retryDelayMs(response, attempt) {
const retryAfter = response.headers.get("retry-after");
if (retryAfter) {
const seconds = Number(retryAfter);
if (Number.isFinite(seconds)) return Math.max(0, seconds * 1000);
const dateMs = Date.parse(retryAfter);
if (Number.isFinite(dateMs)) return Math.max(0, dateMs - Date.now());
}
const capMs = 30_000;
const exponentialMs = Math.min(capMs, 1000 * 2 ** attempt);
return Math.random() * exponentialMs; // Full jitter
}
async function createChatCompletion(body, maxAttempts = 4) {
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
const response = await fetch(
"https://openrouter.ai/api/v1/chat/completions",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
},
);
const raw = await response.text();
let payload;
try {
payload = raw ? JSON.parse(raw) : null;
} catch {
payload = null;
}
if (response.ok) return payload;
const isRateLimit =
response.status === 429 ||
payload?.error?.metadata?.error_type === "rate_limit_exceeded";
if (!isRateLimit || attempt === maxAttempts - 1) {
const error = new Error(payload?.error?.message || raw || `HTTP ${response.status}`);
error.status = response.status;
error.details = payload?.error;
throw error;
}
await sleep(retryDelayMs(response, attempt));
}
}
Эта функция рассчитана на ответы без стриминга. Общую очередь или ограничение параллелизма через token bucket вынесите за её пределы, иначе множество ожидающих воркеров смогут стартовать снова одновременно.
После начала Server-Sent Events с HTTP 200 статус уже не может смениться на 429. Согласно справочнику ошибок OpenRouter, последующий сбой передаётся внутри потока как ошибка с finish_reason: "error". Помечайте такой completion как неуспешный и повторяйте его только при встроенном типе rate_limit_exceeded. Не возвращайте накопленный текст как успешный результат, если приложение явно не поддерживает частичные результаты.
FAQ
Что означает ошибка 429 provider returned error в OpenRouter?
Внешний провайдер инференса отклонил запрос из-за собственного ограничения частоты или доступной мощности. Подтвердить это можно по error.metadata.error_type и метаданным провайдера.
Почему OpenRouter возвращает 429, хотя на балансе ещё есть кредиты?
Аккаунт с пополненным балансом всё равно может получить 429 от внешнего провайдера. Недостаток средств или кредитный лимит ключа обычно возвращают 402.
Сбрасывает ли новый API-ключ OpenRouter лимит запросов?
Нет. Дополнительные ключи не увеличивают глобально регулируемые лимиты. Менять ключ стоит только для устранения проблем с аутентификацией или хранением ключа в клиенте.
Сколько ждать перед повторной попыткой в OpenRouter?
Если есть Retry-After, используйте его. При лимите платформы ориентируйтесь на X-RateLimit-Reset; если нет ни одной подсказки, применяйте ограниченную экспоненциальную задержку со случайным разбросом и небольшим максимумом попыток.
Может ли OpenRouter вернуть HTTP 200, но всё равно завершиться ошибкой 429?
Да, если стриминг уже начался. HTTP-статус останется 200, но поток SSE сообщит об ошибке и завершится с finish_reason: "error". Проверьте встроенный тип ошибки, чтобы установить, было ли причиной ограничение частоты.