Перейти к документации
SDK

Ошибки

Любой сбой выбрасывает исключение. Два класса и идентификатор запроса в каждой ошибке API.

Как его поймать

catch-errors.ts
import { OpenEmailApiError, OpenEmailNetworkError, openemail } from '@openemail/sdk' try {  await openemail.emails.send(message)} catch (error) {  if (error instanceof OpenEmailApiError) {    if (error.isValidation) console.error(error.code, error.param, error.message)    if (error.isPermission) console.error(await openemail.addresses.list())    if (error.isRateLimited) console.error('try again in', error.retryAfterSeconds, 'seconds')     console.error(error.status, error.requestId)  }   if (error instanceof OpenEmailNetworkError && error.isTimeout) console.error('no answer in time')   throw error}

permission_error при отправке — это обычно про область отправки самого КЛЮЧА: домен или адрес, которые ему не выданы, а не про рабочее пространство; поэтому пример печатает то, что addresses.list() сообщает о том, от чьего имени этот ключ может отправлять.

Классы

КлассКогда
`OpenEmailApiError`API ответил, и ответ не был успешным. Несёт status, type, code, param, docUrl, requestId и retryAfterSeconds.
`OpenEmailNetworkError`Ответ не пришёл: DNS, TLS, оборванное соединение, таймаут или ваш собственный AbortSignal. Несёт cause, а isTimeout равно true, когда причиной был таймаут.
`Error`Выбрасывается до того, как что-либо отправлено: отсутствующий или некорректный ключ, непригодный baseUrl, браузер, пустой идентификатор.
ГеттерTrue, когда
`isAuth`type равен authentication_error, 401: ключа нет, учётные данные не того типа или ключ, который выдавали не мы.
`isPermission`permission_error, 403: настоящий ключ без нужной области или без нужного адреса From.
`isScopeMissing`code равен insufficient_scope — тот самый 403, который называет недостающую область.
`isInvalidRequest`invalid_request_error, 400: запрос, который не удалось разобрать. Письмо сверх предельного размера возвращается как 422 message_too_large, поэтому ловит его геттер isValidation.
`isValidation`validation_error, 422: схема отклонила запрос, а param называет поле.
`isNotFound`not_found_error, 404: такого ресурса нет.
`isConflict`conflict_error, 409: ресурс уже прошёл ту точку, в которой с ним можно было это сделать.
`isRateLimited`rate_limit_error, 429. retryAfterSeconds содержит время ожидания, если сервер его назвал.
`isServerError`status равен 500 или выше. При обращении в поддержку укажите requestId.
`isRetryable`status равен 408, 429, 500, 502, 503 или 504.

Геттеры читают type — замороженную половину конверта. code остаётся строкой, потому что API гарантирует, что он открыт и только пополняется; незнакомый код трактуйте по его type. Закрытое объединение сделало бы обновление SDK платой за чтение нового вида отказа.

Тело, которое не является конвертом ошибки API, всё равно становится OpenEmailApiError: type выводится из статуса, а code устанавливается в unrecognised_response. Успешный ответ, тело которого не JSON, тоже приводит к такому исключению.

Прерывание — это тоже OpenEmailNetworkError, произошло оно во время запроса или во время ожидания перед повтором, и само прерывание сохраняется в cause. Проверяйте signal.aborted, когда нужно отличить собственную отмену от сетевого сбоя.

requestId

Каждый OpenEmailApiError несёт идентификатор запроса, присланный сервером, — из тела ошибки или из заголовка x-request-id, и это единственное, что связывает ваш сбой со строкой в логе сервера. Успешный вызов разрешается только разобранным телом, поэтому идентификатора запроса на нём нет.