Коротко
429 - это не ошибка вашего кода и не авария у вендора. Это сообщение «слишком часто, подожди». Проблема начинается тогда, когда код на него реагирует немедленным повтором: вы бьёте в закрытую дверь чаще, лимит не отпускает, и то, что было секундной паузой, превращается в лавину.
Что нужно знать по порядку:
- Лимитов несколько, и упереться можно в любой - запросы в минуту, токены в минуту, параллельные соединения.
- Ответ часто содержит
Retry-After- точное число секунд. Его игнорируют чаще всего. - Повтор должен быть с растущей задержкой и разбросом, иначе все ваши воркеры вернутся одновременно.
- Ретрай не лечит перегрузку - при устойчивом превышении нужна очередь, а не повторы.
Rate limit (лимит частоты) - ограничение на то, сколько запросов или токенов вы можете отправить за единицу времени. Оно есть у каждого вендора моделей и существует, чтобы один клиент не занял мощности всех остальных.
В какой именно лимит вы упёрлись
Одинаковый код 429 приходит на разные превышения, и лечатся они по-разному.

- RPM, запросов в минуту. Упирается тот, кто шлёт много мелких запросов: классификация, извлечение полей, короткие ответы. Лечится склейкой - несколько объектов в один запрос.
- TPM, токенов в минуту. Упирается тот, кто шлёт мало, но огромных запросов: длинный контекст, документы целиком. Лечится сокращением контекста, а не паузами.
- Параллельные запросы. Упирается тот, у кого воркеров больше, чем разрешено соединений. Лечится семафором на своей стороне.
- Дневная или месячная квота. Тут повторы бессмысленны в принципе: до сброса квоты ничего не изменится.
Первое, что стоит сделать при регулярных 429, - посмотреть в тело ответа. Вендоры пишут туда, какой именно лимит сработал, и это экономит день гаданий.
🔴 Отличайте 429 от 529 и 503. 429 - превышение вашего лимита, виноват профиль нагрузки. 529 и 503 - перегрузка на стороне вендора, ваш профиль ни при чём. Ретрай уместен в обоих случаях, но выводы разные: в первом надо править свою нагрузку, во втором - иметь запасную модель.
Retry-After: цифра, которую вам уже дали
Значительная часть ответов с 429 содержит заголовок Retry-After - сколько секунд ждать. Если он есть, гадать не нужно.
import time, random
def retry_after_seconds(err, attempt: int) -> float:
headers = getattr(err, "response", None)
headers = getattr(headers, "headers", {}) or {}
raw = headers.get("retry-after")
if raw:
try:
return float(raw)
except ValueError:
pass
# заголовка нет - экспонента с разбросом
return min(60.0, 2 ** attempt) * (0.5 + random.random())
Две вещи здесь важны одинаково.

Экспонента. Задержка растёт: 1, 2, 4, 8 секунд. Постоянная пауза в секунду при устойчивом превышении не даёт лимиту разжаться никогда.
Разброс (jitter). Множитель 0.5 + random() разносит повторы во времени. Без него двадцать воркеров, получивших 429 в одну секунду, вернутся тоже в одну секунду - и получат 429 снова. Это классическая лавина повторов, и ловится она ровно одной строкой со случайным числом.
Ретрай целиком
RETRIABLE = {429, 500, 502, 503, 529}
def ask(messages, *, model="claude-sonnet-5", attempts=5, **kw):
for attempt in range(attempts):
try:
return client.chat.completions.create(
model=model, messages=messages, **kw
)
except Exception as err:
code = getattr(err, "status_code", None)
if code not in RETRIABLE or attempt == attempts - 1:
raise
delay = retry_after_seconds(err, attempt)
log.warning("%s, повтор через %.1f с (попытка %d)", code, delay, attempt + 1)
time.sleep(delay)
Что тут сделано осознанно:
- Список повторяемых кодов закрыт.
401(неверный ключ),400(кривой запрос) и402(кончились деньги) не повторяются никогда - повтор их не вылечит, а лог засорит. - Попыток пять, не бесконечность. Бесконечный повтор превращает короткий сбой в вечно висящий запрос, который держит соединение и воркер.
- Каждый повтор пишется в лог с кодом и задержкой. Без этого вы не узнаете, что половина запросов уходит со второй попытки, пока не придёт счёт за удвоенное время работы.
🔴 Повторы стоят денег и времени. Неудачный запрос, дошедший до модели, может успеть потратить токены. А пять попыток с экспонентой - это до минуты ожидания в пользовательском сценарии, где терпения секунд десять. Для интерактивных запросов ставьте две попытки и короткий потолок, а длинные цепочки оставьте фоновым задачам.
Когда ретрай не помогает
Повтор рассчитан на короткий всплеск. Если 429 приходит постоянно, вы не в всплеске, а в устойчивом превышении, и повторы только добавляют нагрузки.
Три рабочих выхода:
Ограничьте параллельность у себя. Семафор на количество одновременных запросов - самая дешёвая мера. Двадцать воркеров, каждый со своими повторами, дают лавину; пять воркеров с очередью дают ровный поток.

import asyncio
sem = asyncio.Semaphore(5)
async def ask_limited(messages, **kw):
async with sem:
return await ask_async(messages, **kw)
Склейте мелкие запросы. Если упираетесь в RPM, десять объектов в одном запросе - это десятикратный запас по лимиту при том же объёме токенов. Работает для классификации и извлечения, не работает для диалога.
Разведите нагрузку по моделям. Лимиты считаются на модель, а не на аккаунт целиком. Фоновая массовая обработка на лёгкой модели и интерактивные ответы на флагмане не мешают друг другу.
Что делает шлюз, а что остаётся вам
Часть работы снимает единый шлюз: при отказе провайдера запрос уходит на резервного, а несколько провайдеров одной модели дают суммарный запас по лимитам. Это заметно уменьшает частоту 429, но не отменяет ретрая.
Чего шлюз за вас не делает: не разбирает Retry-After, не ставит паузу в вашем коде и не ограничивает вашу параллельность. Рублёвый баланс и единый ключ упрощают оплату и переключение моделей - на профиль вашей нагрузки они не влияют никак. Ретрай и семафор пишутся на вашей стороне в любом случае.
С чего начать
- Залогируйте коды ответов за неделю. Пока вы не знаете свою долю 429, всё остальное - догадки.
- Прочитайте
Retry-Afterи используйте его вместо своей константы. - Добавьте экспоненту с разбросом - это две строки и самый большой эффект.
- Поставьте семафор на параллельные запросы, число подберите замером.
- Разделите интерактивную и фоновую нагрузку - по моделям и по числу попыток.
Все 44 модели с ценами и контекстом - на витрине. Разбор конкретных кодов Anthropic - в ошибках Claude API, а про запасную модель на случай отказа - в маршрутизации.
FAQ
Что означает ошибка 429 Too Many Requests?
Что вы превысили разрешённую частоту обращений: слишком много запросов, слишком много токенов за минуту или слишком много одновременных соединений. Это штатный ответ сервиса, а не поломка вашего кода и не авария у вендора.
Как правильно повторять запрос после 429?
С растущей задержкой и случайным разбросом: 1, 2, 4, 8 секунд, каждая умноженная на случайный множитель. Если в ответе есть заголовок Retry-After, брать паузу из него. Повторять сразу или через фиксированную секунду - худший вариант, он поддерживает превышение.
Чем 429 отличается от 529?
429 говорит, что превышен ваш личный лимит - надо править свой профиль нагрузки. 529 (и 503) говорят, что перегружен сам вендор, и ваша нагрузка ни при чём. Повторять стоит оба, но во втором случае помогает переключение на другую модель, а не пауза.
Почему после добавления ретрая стало хуже?
Скорее всего, повторы уходят без разброса: все воркеры получили 429 одновременно и одновременно же вернулись. Плюс каждый повтор - это дополнительный запрос к тому же лимиту. Лечится случайным множителем в задержке и ограничением параллельности.
Как понять, в какой лимит я упёрся?
По телу ответа: вендоры указывают, какой лимит сработал - запросы в минуту, токены в минуту или параллельные соединения. Косвенно - по профилю: много мелких запросов означает упор в RPM, мало больших - в TPM.
Убирает ли агрегатор ошибки 429?
Уменьшает, но не убирает. Несколько провайдеров одной модели дают суммарный запас по лимитам и подмену при отказе. Но Retry-After за вас никто не прочитает и параллельность вашего кода не ограничит - ретрай нужен всё равно.