Telegram Bots

Debugging a Telegram Bot That Stops Responding

A systematic way to find out why a Telegram bot has gone quiet — process health, 409 conflicts, webhooks, frozen event loops, crashes, privacy mode and revoked tokens.

On this page
  1. Step 1: Is the process running?
  2. Step 2: Is the token still valid?
  3. Step 3: Is something else receiving the updates?
  4. Step 4: Is the polling loop still alive?
  5. Step 5: Is the event loop frozen?
  6. Step 6: Is it running out of memory?
  7. Step 7: Is it only groups?
  8. Step 8: Is it rate limited?
  9. Step 9: Is the database stuck?
  10. Prevent the next silent failure
  11. A quick checklist
  12. Summary

Your Telegram bot was working yesterday. Today it ignores every message. No error in chat, no obvious clue — just silence. The good news: there are only a handful of reasons a bot stops responding, and you can check them in order in a few minutes.

Step 1: Is the process running?

Open your host’s console. You’re looking for one of three situations:

  • The process isn’t running. Start it and watch the first lines of output — a crash on startup (missing variable, missing dependency, syntax error) will show immediately.
  • The process is restarting over and over. Scroll up to the first error. Crash loops almost always come from something in the first few seconds of startup.
  • The process is running and quiet. Move on to the next steps.

On Kerit Cloud, a watchdog restarts crashed processes within seconds and keeps the error in the live console, so a crash usually shows up as a short gap and a stack trace rather than a dead bot.

Step 2: Is the token still valid?

A quick check from any terminal:

curl -s "https://api.telegram.org/bot$BOT_TOKEN/getMe"
  • {"ok":true,...} — the token works.
  • 401 Unauthorized — the token was revoked or mistyped. If you (or someone with access) used /revoke in BotFather, update the environment variable with the new token.

Step 3: Is something else receiving the updates?

This is the most common cause of a “silent” bot.

Another copy is polling

Only one process can call getUpdates for a bot at a time. If a second copy is running — on your laptop, an old server, or a forgotten deployment — Telegram splits or steals the updates, and logs show:

Conflict: terminated by other getUpdates request; make sure that only one bot instance is running

Find and stop the other copy. If you can’t find it, revoke the token in BotFather and set the new one only on your real server — the stray copy will stop working instantly.

A webhook is set

If a webhook is registered, polling receives nothing (and may log 409 Conflict: can't use getUpdates method while webhook is active). Check:

curl -s "https://api.telegram.org/bot$BOT_TOKEN/getWebhookInfo"

A non-empty url means updates are going there. If you meant to poll, call deleteWebhook. If you meant to use the webhook, read last_error_message — it tells you why Telegram can’t deliver (timeouts, SSL errors, wrong status codes). See setting up a Telegram webhook over HTTPS.

Step 4: Is the polling loop still alive?

A process can be running while its polling loop has quietly ended. Classic causes:

  • telebot’s polling() stops on certain network errors, leaving the process alive but deaf. Use infinity_polling(), which restarts polling after errors.
  • grammY without bot.catch stops the bot on the first unhandled error. Register an error handler.
  • Telegraf without bot.catch can let an error escape and stop processing.
  • A top-level try/except that swallows the error and exits the loop without exiting the process.

The fix is always the same: make errors in individual updates get logged and skipped, not fatal to the loop. If the loop truly must end, let the process exit so the supervisor restarts it.

Step 5: Is the event loop frozen?

In async bots — aiogram, grammY, Telegraf, Telethon — one blocking call freezes everything, including receiving new updates. Typical culprits:

  • time.sleep() instead of await asyncio.sleep() in Python.
  • requests.get() instead of an async client like aiohttp or httpx.AsyncClient.
  • Heavy CPU work (image processing, big loops) directly in a handler.
  • Synchronous database drivers inside async handlers.
  • In Node.js, synchronous file operations (fs.readFileSync on big files) or tight loops.

A frozen loop looks like a running process with no new log lines. Add a heartbeat — a log line every minute from a background task. If the heartbeat stops too, the loop is blocked. In Python, running with PYTHONASYNCIODEBUG=1 makes asyncio warn about slow callbacks.

Step 6: Is it running out of memory?

If the process gets killed for exceeding its memory limit, it restarts — and if the leak is steady, it happens again and again. Look at the memory graph in your panel: a sawtooth pattern (climb, drop, climb, drop) means repeated out-of-memory kills. Common causes are in-memory session stores growing with every chat, caches without size limits and media held in memory. See storing Telegram bot state and handling files and media.

Step 7: Is it only groups?

If the bot answers in private chat but ignores a group, it’s probably privacy mode. With privacy mode on (the default), a bot in a group only receives:

  • commands (/something),
  • replies to its own messages,
  • messages that mention it.

A bot that should react to ordinary messages needs privacy mode disabled in BotFather (/setprivacy → Disable). After changing it, remove the bot from the group and add it back — the setting applies when the bot joins.

Also check that the bot is still a member, hasn’t been restricted, and has permission to send messages in that group or topic.

Step 8: Is it rate limited?

If the bot sends a lot — broadcasts, busy groups — Telegram may respond with 429 Too Many Requests and a retry_after. A bot that waits correctly seems slow; one that retries badly can stay limited for a long time. Look for 429s in the logs and see Telegram Bot API limits.

Step 9: Is the database stuck?

Handlers that wait on a database will hang if the database does. Check for:

  • database is locked errors with SQLite — usually two processes sharing one file, or a long transaction never committed.
  • Connection pool exhaustion — every handler waiting for a connection that never frees up because an earlier handler didn’t release it.
  • The database being unreachable after a credentials change.

Prevent the next silent failure

  • Log every update’s handling time at debug level, and every error at error level.
  • Log a heartbeat from a background task every minute.
  • Monitor from outside. An uptime monitor that calls a small health endpoint — or a scheduled check that the bot answers — alerts you before users do. See setting up uptime monitoring.
  • Run exactly one production copy, and use a separate bot token for testing.

A quick checklist

  1. Process running? First error in the console?
  2. getMe works?
  3. Another copy polling? Webhook set?
  4. Polling loop protected by an error handler?
  5. Any blocking calls in async code?
  6. Memory sawtooth in the graph?
  7. Group-only problem → privacy mode?
  8. 429s in the logs?
  9. Database locks or pool exhaustion?

Summary

A silent Telegram bot is almost always one of: a stopped or crash-looping process, a revoked token, a second copy or a webhook stealing updates, a polling loop ended by an unhandled error, a frozen event loop, out-of-memory restarts, privacy mode in groups, rate limits or a stuck database. Check them in that order, then add heartbeats and external monitoring so the next failure announces itself.