Skip to content

Решение проблем

Сгруппировано по симптому: что вы видите → почему так → как починить.

Бот запускается, но не получает обновлений

  • 409 Conflict: terminated by other getUpdates request — два процесса делают long-polling одного токена (второй bot.start(), старый контейнер ещё работает, или поллинг при установленном webhook). Запускайте ровно один экземпляр. Если ранее устанавливали webhook, вызовите bot.api.deleteWebhook() перед поллингом.
  • Установлен webhook, поэтому поллинг ничего не получает. Webhook и long-polling взаимоисключающи. Вызовите deleteWebhook, чтобы вернуться к поллингу, либо оставьте webhook и не вызывайте обычный bot.start().
  • Не приходят opt-in обновления (chat_member, message_reaction, chat_join_request, business-обновления). Telegram исключает их из allowed_updates по умолчанию. Передайте их явно:
    ts
    bot.start({ allowedUpdates: ["message", "chat_member", "message_reaction"] });
    См. Обновления.
  • В группах бот видит только команды и @упоминания. Privacy mode включён по умолчанию. Отключите его через /setprivacy в @BotFather — только если бот должен читать все сообщения группы.

401 / 404 от API

  • 401 Unauthorized — неверный или пустой токен. new Bot(process.env.BOT_TOKEN as string) молча станет undefined, если переменная окружения отсутствует. Убедитесь, что токен загружен (например, node --env-file=.env, dotenv или секреты вашего хостинга) до создания бота.
  • 404 Not Found на каждом методе — обычно неверный базовый URL API (опечатка в кастомном / локальном Bot API) или токен с лишним пробелом/переводом строки.

Сломано форматирование (литеральные теги, нет жирного, двойное экранирование)

Это самые частые ошибки в GramIO — полные правила в Форматировании.

  • Вы видите литеральные <b> / * / обратные слэши в сообщении. Вы передали parse_mode вместе с шаблоном format. Никогда не сочетайте их — format уже создаёт настоящие сущности. Уберите parse_mode полностью.
  • Сущности пропадают при объединении массива formattable. Нативный Array.prototype.join() превращает в строку и срезает сущности. Используйте хелпер join из gramio.
  • Сущности пропадают при переиспользовании FormattableString. Обычная интерполяция шаблона (`${myFormattable}`) срезает сущности; не вызывайте на нём .toString(). Всегда оборачивайте переиспользуемые formattable во внешний format`...` .
  • Форматирование подписи игнорируется на медиа. Передавайте значение format как caption — и снова, без parse_mode.

Callback-кнопки «сломаны» / висит индикатор

  • Инлайн-кнопка показывает индикатор загрузки ~15с. Обработчик не вызвал answerCallbackQuery. Сделайте await ctx.answer() первой строкой каждого callbackQuery-обработчика (пустой ответ — это нормально) или установите @gramio/auto-answer-callback-query. См. UX-паттерны §7.
  • callbackQuery-обработчик не срабатывает. callback_data кнопки не совпадает с матчером обработчика. Предпочтите типизированную схему CallbackData и передавайте один и тот же экземпляр в .pack() и в bot.callbackQuery(schema, …). См. Инлайн-клавиатуру.
  • BUTTON_DATA_INVALID. callback_data превышает 64 байта. Сократите схему / упаковывайте меньше полей.

Сцены / многошаговые потоки

  • ctx.scene undefined / сцены ничего не делают. scenes() требует, чтобы session() был установлен первым: .extend(session()).extend(scenes([...])). См. Сцены.
  • Поток молча сбрасывается после деплоя или рестарта. Вы использовали @gramio/prompt (в памяти) для многошагового потока. Ожидаемый промис умирает вместе с процессом. Используйте .ask() у Сцен (сохраняет шаг + ответы через storage) для всего, что должно пережить рестарт.

Доступ к контексту

  • ctx.payload / snake_case-поля undefined или без типов. Не читайте сырой payload. Каждое поле Telegram — это camelCase-геттер на контексте: ctx.from.firstName, ctx.chatId, ctx.messageId.
  • Ожидаемый геттер undefined. Он есть только на соответствующем типе обновления — сначала сузьте через ctx.is("message") или фильтр, затем обращайтесь.

Загрузка файлов

  • sendPhoto падает или отправляет литеральную строку пути. MediaUpload.path / url / bufferасинхронный, его нужно await:
    ts
    await ctx.sendPhoto(await MediaUpload.path("./p.jpg"));
    Уже загруженный file_id передаётся напрямую (без MediaUpload). См. Файлы.

Webhook не срабатывает

  • Telegram не обращается к вашему эндпоинту. bot.start({ webhook: { url } }) вызывает setWebhook, но не запускает HTTP-сервер — вы должны сами смонтировать webhookHandler(bot, "<framework>") и выставить его по HTTPS. Проверьте через bot.api.getWebhookInfo() (смотрите last_error_message). См. Webhook.
  • Локальная разработка: Telegram не достучится до localhost. Используйте туннель (cloudflared / ngrok) и установите webhook на публичный HTTPS-URL.

Не проходит авторизация Mini App (TMA)

  • Не проходит валидация initData. Расхождение часов, неверный токен бота в валидаторе или вы валидируете уже распарсенный объект вместо сырой строки initData. Валидируйте сырую строку правильным токеном. См. Mini Apps.

Типы / сборка

  • Кастомный ctx.fooany или ошибка. Не дополняйте через declare module. Добавляйте через .derive(ctx => ({ foo })) (на обновление) или .decorate({ foo }) (статически), чтобы тип проходил автоматически.

Всё ещё не получается?