Ошибки и лимиты
Формат ошибок REST, частые коды для ботов и что с ними делать, лимиты частоты и тарифа, повторы и идемпотентность.
Формат ошибки
Любой ответ не из диапазона 2xx несёт тело ApiError:
{
"code": "ERROR_CODE_FORBIDDEN",
"message": "not available for bots",
"field": "",
"reason": "BOT_NOT_ALLOWED"
}| Поле | Что это |
|---|---|
code | код из перечисления ErrorCode — по нему ветвитесь |
message | текст для логов, не для разбора: формулировка может меняться |
field | поле запроса (lowerCamelCase) для ERROR_CODE_VALIDATION и некоторых конфликтов |
reason | уточнение, когда у кода несколько причин: BOT_NOT_ALLOWED, PLAN_LIMIT, FEATURE_DISABLED… |
used · limit | счётчик и предел, если ошибка про лимит |
Полный список кодов — Коды ошибок.
Частые ошибки ботов
| HTTP | code / reason | Что значит | Что делать |
|---|---|---|---|
| 400 | ERROR_CODE_BAD_REQUEST | битый JSON или параметры | исправить запрос |
| 401 | ERROR_CODE_UNAUTHENTICATED | токена нет, он неверный, отозван или перевыпущен | остановиться, получить новый токен |
| 403 | ERROR_CODE_FORBIDDEN, reason: "BOT_NOT_ALLOWED" | маршрут только для людей | не повторять — см. что закрыто ботам |
| 403 | ERROR_CODE_FORBIDDEN | не хватает права; message называет какого | выдать боту роль или переопределение |
| 403 | ERROR_CODE_BOT_BLOCKED | человек заблокировал бота | не писать этому человеку |
| 403 | ERROR_CODE_WORKSPACE_SUSPENDED | пространство приостановлено: писать нельзя, читать можно | ждать снятия |
| 404 | ERROR_CODE_NOT_FOUND | объекта нет — или он скрыт от бота | проверить VIEW_ROOM / VIEW_BOARD и переопределения |
| 409 | ERROR_CODE_CONFLICT, reason: "PLAN_LIMIT" | лимит тарифа (used / limit) | освободить место или сменить тариф |
| 409 | ERROR_CODE_CONFLICT, reason: "REACTION_LIMIT" | не больше 3 разных реакций одного участника на сообщение | убрать реакцию |
| 409 | ERROR_CODE_CONFLICT, reason: "FEATURE_DISABLED" (field) | функция доски выключена, а запрос ставит её поле | не передавать поле или включить функцию |
| 409 | ERROR_CODE_ROOM_FULL | голосовая комната заполнена | подождать |
| 413 | ERROR_CODE_FILE_TOO_LARGE · …_FILE_QUOTA_EXCEEDED · …_PAYLOAD_TOO_LARGE | размер или квота | уменьшить файл |
| 422 | ERROR_CODE_VALIDATION (field) | неверное значение поля | исправить поле |
| 429 | ERROR_CODE_RATE_LIMITED + Retry-After | превышен лимит частоты | подождать Retry-After секунд и повторить с тем же nonce |
| 503 | ERROR_CODE_UNAVAILABLE | временный сбой | повторить с задержкой |
Лимиты
| Что | Значение |
|---|---|
| Запросы бота | 30 в секунду (всплеск — 30) |
| Сообщения бота | 20 в минуту по всем комнатам и DM, плюс общий лимит 5 сообщений за 5 с на комнату |
| Новые DM | 10 сразу, 30 в час |
| Загрузка файлов | 30 сразу, 120 в час; размер и квота — по тарифу |
| Сообщение | до 4000 символов, до 20 вложений, nonce — до 64 символов |
| Команды | до 100, имя до 32 символов, описание до 256 |
| Gateway | 1 сокет на токен, кадр до 64 КиБ |
| Ботов в пространстве | по тарифу: Free — 1, Team — 5, Business — 20; бот занимает и место участника |
Запросов в секунду и сообщений в минуту хватает для интеграций, но не для массовых рассылок. На своём сервере оператор может поменять лимиты бота переменными BOT_RATE_PER_SEC и BOT_MESSAGES_PER_MIN. Все лимиты — Лимиты.
Повторы и идемпотентность
429— ждитеRetry-Afterсекунд и повторяйте. SDK делает это сам доmaxRetriesраз.5xxи обрывы сети — повторяйте с экспоненциальной задержкой.- Сообщения отправляйте с
nonce: повтор с тем жеnonceвернёт уже созданное сообщение (200) вместо дубля. - Формы отправляйте с постоянным UUID-
nonce: одинаковые отправки создают одну задачу. - События (gateway, вебхук) могут прийти повторно — дедуплицируйте по
idдоставки,seqилиidнажатия. 4xxкроме429не повторяйте без изменения запроса.
async function call(url, init, tries = 5) {
for (let i = 0; ; i++) {
const res = await fetch(url, init);
if (res.status !== 429 && res.status < 500) return res;
if (i === tries - 1) return res;
const wait = Number(res.headers.get('Retry-After')) || 2 ** i;
await new Promise((r) => setTimeout(r, wait * 1000));
}
}import time, requests
def call(method, url, tries=5, **kw):
for i in range(tries):
r = requests.request(method, url, **kw)
if r.status_code != 429 and r.status_code < 500 or i == tries - 1:
return r
time.sleep(float(r.headers.get("Retry-After", 2 ** i)))Частые вопросы
Бот не видит комнату или сообщения. Нет VIEW_ROOM: комната приватная, закрытая (только через переопределение на ней) или роль бота не даёт доступа. Проверьте роли и переопределения комнаты.
Бот не отвечает на /cmd. Команду никто не зарегистрировал, или её зарегистрировали несколько ботов комнаты — пишите /cmd@username. Сообщения ботов командами не бывают.
Нужен ли gateway, если есть вебхук? Нет. Бот на вебхуке работает через REST и вебхук и считается в сети, пока делает запросы. Но события голоса приходят только через gateway.
Два процесса с одним токеном? Нельзя — второй вытесняет первый. Для масштабирования — вебхук с обработкой по id или несколько ботов.
Слышит ли бот себя в звонке? Нет: LiveKit не отправляет участнику его собственные дорожки. SDK по умолчанию пропускает собственные сообщения и реакции бота (receiveOwn: true включает их).