Ошибки
Обрабатывайте HTTP-статус и машинный error.code, а не сравнивайте полный текст сообщения. Текст предназначен человеку и может уточняться.
{
"error": {
"message": "Безопасное описание ошибки",
"type": "neuroapi_error",
"code": "upstream_unavailable"
}
}| HTTP | Код | Действие | Повтор |
|---|---|---|---|
| 400/422 | invalid_request / invalid_video_request | Исправить поля, формат или несовместимое сочетание параметров. | Нет |
| 400 | invalid_external_media | Проверить публичную HTTPS-ссылку либо передать Base64/data URL. | Нет |
| 403 | pre_consume_token_quota_failed | Пополнить баланс или проверить лимит ключа. | Нет |
| 403 | moderation_blocked | Провайдер отклонил содержимое; переформулировать запрос или убрать спорное медиа. | Нет |
| 429 | rate_limit_exceeded | Снизить параллелизм и повторить с задержкой. | Да |
| 503 | upstream_unavailable | Сервис генерации временно перегружен; повторить с backoff. | Да |
| 5xx | internal_error | Временная ошибка NeuroAPI; повторить с backoff и сохранить request id. | Да |
Когда повторять
Повторяйте только явно полученные временные 429/502/503/504. Используйте экспоненциальную задержку, jitter и ограничение числа попыток. Сетевой таймаут после отправки тела запроса может означать, что генерация уже началась: не повторяйте создающий POST вслепую.
Когда не повторять
400/422, цензура, неверные медиа и недостаток баланса требуют действия пользователя. Автоматический повтор только создаст лишнюю нагрузку.
const retryable = new Set([429, 502, 503, 504]);
async function requestWithBackoff(run: () => Promise<Response>) {
for (let attempt = 0; attempt < 3; attempt += 1) {
const response = await run();
if (response.ok || !retryable.has(response.status)) return response;
if (attempt === 2) return response;
const retryAfter = Number(response.headers.get("retry-after"));
const delay = Number.isFinite(retryAfter)
? retryAfter * 1000
: 1000 * 2 ** attempt + Math.random() * 300;
await new Promise((resolve) => setTimeout(resolve, delay));
}
throw new Error("unreachable");
}Медиа по внешней ссылке
Ссылка может быть недоступна, слишком медленна либо затронута сетевой фильтрацией и ТСПУ Роскомнадзора. Проверьте, что URL публичный и открывается без cookie/авторизации. Для небольших файлов надёжнее скачать их в приложении и передать Base64.