English · Русский

Обработка ошибок

См. также: index.md (индекс) · developer-guide.md (быстрый старт, выпуск ключа, примеры запросов) · security-model.md (localhost, модель ключей, аудит) · versioning-and-deprecation.md (политика semver).

Каждый ответ с ошибкой несёт тело JSON ApiError (Common.ApiError в контракте):

{
  "error": "forbidden",
  "message": "Insufficient tier or missing scope",
  "required": { "tier": 2, "scopes": ["task:control"] },
  "current": { "tier": 0, "scopes": ["task:read"] }
}

required/current (AuthRequirement: тир + скоупы) заполняются только при 403; при любом другом статусе они отсутствуют (только message, либо null).

Коды статусов и машиночитаемые коды ошибок

Большинство кодов ниже — это реальные константы из Common.ApiError.ApiErrorCodes / Common.ApiError.ApiStatus; два (not_implemented, service_unavailable) — буквальные строки, которые шлюз авторизации пишет напрямую, а не общие константы — это отдельно отмечено, поскольку это реальная, хоть и небольшая, несогласованность в текущем коде, а не ошибка документации. Если будущее изменение добавит код, добавляйте его сюда в том же PR.

HTTP статус код ошибки Значение Источник
400 bad_request Некорректно сформированный запрос (плохой JSON, неверный параметр). Любая операция, валидация формы запроса.
401 unauthorized Отсутствует или невалиден Authorization: Bearer <api-key> — нет ключа, неизвестный ключ, либо истёкший/отключённый. Шлюз авторизации (AuthGate.EvaluateAuthDecision.Unauthenticated), любая операция кроме ping.
403 forbidden Ключ валиден, но не хватает требуемого скоупа, либо тир операции превышает maxTier ключа. Тело включает required/current. Шлюз авторизации (OperationAuthorizer.AuthorizeAuthDecision.Forbidden).
404 not_found Три разных источника, один код: (a) путь/глагол не сопоставляется ни с одной известной операцией; (b) на хосте ZennoPoster операция была распознана и авторизована, но задача, инстанс, вкладка или элемент, к которым она обращается, не существуют — например GET /tasks/{id} с неизвестным id; (c) на хосте ProjectMaker в открытом проекте нет действия, переменной, списка, таблицы или Google-таблицы с таким именем, либо файл в POST /projects/open не существует. «Проект вообще не открыт» — это не 404, см. project_not_open. (a) Шлюз авторизации; (b) обработчики домена ZennoPoster/Instance; (c) обработчики домена ProjectMaker.
409 project_not_open Любой операции /projects/current/* на хосте ProjectMaker нужен открытый проект, а в редакторе его нет (например, до открытия первого проекта). Сначала откройте или создайте проект (POST /projects/open, POST /projects). Обработчики домена ProjectMaker.
409 failed_precondition Открытый проект не в том состоянии, чтобы выполнить вызов: POST /projects/current/close при несохранённых изменениях без discardUnsavedChanges: true или во время выполнения/отладки; POST /projects/current/save, когда целевой файл существует и пользователь отказался его перезаписать. Обработчики домена ProjectMaker.
404 session_not_found GET/POST /api/v1/sessions/{id} — нет открытого окна WaitForUserAction с таким id. Домен сессий, только хост ZennoPoster.
409 no_active_interaction POST /sessions/{id}/complete обращается к окну WaitForUserAction, которое уже не открыто — уже завершено, либо окно/задача закрылись. Вызовы instance:interact эту ошибку не возвращают: управление вкладками/DOM не требует открытой сессии. Домен сессий, только хост ZennoPoster.
409 session_expired Объявлено в контракте для сессии, чьё окно закрылось до вызова complete. Пока ни одним путём кода не выбрасывается — ни одна сессия в текущей реализации не переходит в это состояние; считайте это зарезервированным на будущее, а не кодом, который вы реально увидите в v1. Домен сессий (зарезервировано).
409 dom_unavailable GET /instances/{id}/tabs/{tabId}/dom — текст DOM прямо сейчас не удалось получить (например, страница в процессе навигации). Повторите попытку, а не считайте это постоянным сбоем. Домен Instance, только хост ZennoPoster.
409 instance_busy DELETE /instances/{id} — порт принадлежит рабочему потоку выполняющейся задачи и не может быть освобождён через API. Домен Instance.
409 instance_view_protected POST /instances/{id}/show — вид браузера защищён (защита вида включена и нет открытого окна WaitForUserAction), окно не может быть показано. Домен Instance.
409 task_scheduler_owned DELETE /tasks/{id} — задача принадлежит джобу планировщика и не может быть удалена напрямую; удаляйте джоб планировщика. Домен задач, только хост ZennoPoster.
413 payload_too_large Тело запроса превышает лимит загрузки хоста (по умолчанию 2 ГБ — предохранитель, а не то, во что упирается обычное использование). Применяется к любой операции с телом JSON на хосте ZennoPoster. Хост ZennoPoster, глобальная защита размера тела запроса (не бизнес-логика конкретной операции).
429 rate_limited Слишком много конкурентных long-poll’ов GET /sessions/events (лимит на хост, по умолчанию 32); также зарезервировано для rate-limiting удалённого режима. Long-poll событий сессий; удалённый режим/TLS (пока не включён).
500 internal_error Необработанный сбой на стороне сервера. Любая операция.
501 not_implemented Шлюз распознаёт путь/глагол как объявленную операцию, но OperationDescriptor.IsImplemented == false — она не подключена к обработчику на этом хосте (например, HITL-трио confirmations_*). Шлюз авторизации (AuthDecision.NotImplemented).
503 service_unavailable Главный выключатель среды выполнения AI/PublicApi отключён — любой вызов отклоняется ещё до проверки ключа. Шлюз авторизации, проверяется до деталей ключа/операции.

Заметка о 409

Сам шлюз авторизации никогда не возвращает 409 — согласно собственной документации Auth.HttpListener, он выдаёт только 401 / 403 / 404 / 501 (осознанное решение: отказы авторизации не получают статус «конфликт»). 409 — статус уровня домена, возвращаемый только доменом sessions/instance, когда вызов вполне авторизован, но нужный ему контекст времени выполнения (открытое окно взаимодействия) отсутствует. Не путайте эти два случая: 403 означает «ваш ключ не может это сделать»; 409 означает «ваш ключ может это сделать, но не прямо сейчас».

Чек-лист обработки для интегратора

  • 401 — ключ отсутствует, неверен, истёк или был отозван. Выпустите ключ повторно через UI; слоя обновления нет (непрозрачные ключи, без обмена токенами).
  • 403 — сравните required и current в теле и либо запросите ключ с недостающим скоупом/тиром, либо не выполняйте этот вызов. Не повторяйте попытку без изменений; с тем же ключом она никогда не пройдёт.
  • 404 / 409 в домене sessions/instance — это ожидаемо, а не исключительно: окно WaitForUserAction может закрыться между вашим GET /sessions и вызовом POST /sessions/{id}/complete. Перед повтором заново получите список и убедитесь, что сессия ещё открыта.
  • 429 — снижайте частоту; актуально для long-poll GET /sessions/events (лимит конкурентных поллов) и, в будущем, для удалённого режима.
  • 501 — операция объявлена в контракте, но не подключена на этом хосте (isAvailable: false в /capabilities для этого operationId); не вызывайте её.
  • 503 — главный выключатель AI/PublicApi отключён на стороне хоста; ничто не заработает, пока его не включат снова. Клиент этого обойти не может.
  • 409 dom_unavailable — временная ситуация; повторите вызов получения текста DOM, а не считайте это постоянным сбоем.
  • 413 — тело вашего запроса превышает лимит загрузки хоста; это предохранитель (по умолчанию 2 ГБ), а не обычный лимит использования — если вы в него упёрлись, вероятно, что-то не так на стороне клиента.

Всегда сначала проверяйте GET /api/v1/capabilities (см. «Руководство разработчика»), чтобы избежать 403/501, которые можно было предсказать на стороне клиента.


Generated from the frozen operation catalog of ZennoPoster. Questions and issues — github.com/ZennoLab/zennoposter-mcp/issues

This site uses Just the Docs, a documentation theme for Jekyll.