Ошибки и повторы
Конверт ошибки
Любой ответ не 2xx приходит в одном конверте, во всех операциях одинаковом:
{
"error": {
"code": "VERSION_CONFLICT",
"message": "The conversation has changed",
"request_id": "3f2b0c9e8d7a4b6c9e1f2a3b4c5d6e7f",
"retryable": false,
"outcome": "not_applied",
"details": { "version": 7 },
"field_errors": null
}
}
| Поле | Что это |
|---|---|
code | машинный код: по нему и решают, что делать. Перечень — ниже и в схеме ErrorCode справочника |
message | текст для журнала разработчика, на английском; показывать его людям не нужно |
request_id | id запроса, он же заголовок ответа X-Request-ID: назовите его в обращении в поддержку, по нему находится запись в журналах установки |
retryable | true — запрос можно повторить после паузы (с тем же Idempotency-Key) |
outcome | подействовала ли команда: not_applied, applied или unknown |
details | скаляры, уточняющие отказ: id, версии, лимиты (retry_after, received_bytes) |
field_errors | ошибки полей тела или параметров: field (путь, например customer.external_id), code, message |
Коды
| Ответ | code | Что делать |
|---|---|---|
400 | BAD_REQUEST | неверный запрос, например нет Idempotency-Key у изменяющего вызова |
401 | UNAUTHENTICATED | получить новый токен (аутентификация) |
403 | FORBIDDEN | роли не хватает права; повтор не поможет |
403 | FEATURE_NOT_LICENSED | модуль не входит в лицензию установки |
404 | NOT_FOUND | объекта нет или он вне организации (никогда не 403) |
409 | VERSION_CONFLICT | устаревшая expected_version: перечитать обращение и решить заново |
409 | STATE_TRANSITION_NOT_ALLOWED | действие не подходит к состоянию объекта, например сообщение в обращение не из API |
409 | IDEMPOTENCY_KEY_REUSED | ключ уже использован с другим запросом: ошибка клиента, нужен новый ключ |
409 | OPERATION_IN_PROGRESS | запрос с этим ключом ещё выполняется: повторить после Retry-After |
409 | ATTACHMENT_NOT_READY, UPLOAD_OFFSET_MISMATCH | файл ещё проверяется антивирусом; часть загрузки не с того места (обзор) |
410 | RESYNC_REQUIRED | история обращения перестроена: начать чтение заново, без курсора |
413 | PAYLOAD_TOO_LARGE | тело больше допустимого |
422 | VALIDATION_FAILED | неверное значение: смотреть field_errors |
429 | RATE_LIMITED | превышен лимит частоты: ждать Retry-After |
503 | OUTCOME_UNKNOWN | неизвестно, выполнилась ли команда: повторить с тем же ключом |
503 | DEPENDENCY_UNAVAILABLE | недоступна зависимость установки: повторить позже |
500 | INTERNAL | ошибка сервера; outcome = unknown |
Новые коды могут появиться в следующих версиях: неизвестный код обрабатывайте по статусу HTTP и retryable.
Когда повторять
retryable = true— повторите после паузы:Retry-Afterв секундах, если он есть, иначе экспонента с джиттером.outcome = unknown— неизвестно, выполнилась ли операция. Повторите с тем жеIdempotency-Key: если она выполнилась, сервер вернёт её первый ответ.outcome = not_appliedиretryable = false— команда не подействовала, и тот же запрос не пройдёт: исправьте его.
SDK повторяют только безопасное: чтения и запросы с ключом. Повторяются обрыв соединения и таймаут, ответ с retryable = true или OUTCOME_UNKNOWN, 429, 502, 503, 504.
Idempotency-Key
Каждый изменяющий вызов требует заголовок Idempotency-Key (в справочнике он отмечен у операции):
- значение — уникальная строка на операцию, от 1 до 255 видимых символов ASCII; обычно UUID или id команды в вашей системе;
- без заголовка —
400 BAD_REQUEST; - повтор с тем же ключом и тем же запросом не выполняет операцию второй раз и возвращает первый ответ;
- тот же ключ с другим телом или адресом —
409 IDEMPOTENCY_KEY_REUSED; - повтор, пока первый запрос выполняется, —
409 OPERATION_IN_PROGRESSсRetry-After; - ключ действует в пределах сервисного аккаунта и операции и хранится 30 дней.
Без ключа идут только части загрузки файла: место части задаёт Content-Range, и повтор той же части получает 409 UPLOAD_OFFSET_MISMATCH с received_bytes.
SDK ставят новый UUID на вызов и тот же — на все его повторы. Свой ключ передают последним аргументом метода.