WeMAIdeStart a project ↗

WEMAIDE / INSIGHTS / ENGINEERING

Telegram bot not sending messages? Trace the failure before restarting it

Diagnose Telegram Bot API failures by separating incoming updates, application processing, outgoing requests and delivery. Includes a safe troubleshooting record.

Engineering11 min read
Telegram bot infrastructure and integration components

When a Telegram bot stops replying, a restart is a guess. First find the boundary that stopped working: did Telegram produce an update, did your application receive it, did the handler finish, and did Telegram accept the outgoing message? A bot that receives nothing needs a different fix from a bot whose sendMessage request fails.

This guide covers the Telegram Bot API and a bot you operate. It is a diagnostic procedure, not a report of a particular client outage. Use a test chat whose participant expects the test, preserve pending work, and keep credentials and personal message content out of shared logs.

A quick first test when the bot is not responding

Use one expected test participant and one deployment. Confirm the bot with getMe, inspect getWebhookInfo, send /start in the intended chat and trace that event to one plain-text reply. Run API calls from your secured server tooling; do not paste a token-bearing URL into the browser or a shared ticket. The fixtures below are synthetic responses, not logs from a client incident.

Synthetic getWebhookInfo response A
{"ok":true,"result":{"url":"","pending_update_count":0}}

Synthetic getWebhookInfo response B
{"ok":true,"result":{
  "url":"https://bot.example.invalid/updates",
  "pending_update_count":12,
  "last_error_message":"Wrong response from the webhook: 502 Bad Gateway"
}}

Synthetic sendMessage result
{"ok":true,"result":{"message_id":42,"chat":{"id":123,"type":"private"},"date":1800000000,"text":"Test"}}
Read the response, then choose the next check
Observed resultNext checkUseful retest evidence
A: no webhook URLVerify the intended polling worker is running and no competing process consumes its updatesThe new /start update reaches the intended handler
B: pending updates plus a recent 502Inspect the HTTPS endpoint, proxy and application error at that time; preserve queued workThe delivery error stops recurring and the known event reaches durable intake
409 on getUpdatesRead its description: active webhook and competing poller conflicts require different configuration checksOnly the intended transport/consumer handles the test event
403 on a private-chat sendCheck the exact description, bot identity and whether the participant started or blocked this botA consenting test participant receives the intended plain reply
429 with parameters.retry_after = 18Wait at least 18 seconds, then revalidate the queued operation; this is an example delayA bounded retry after the delay has a recorded result
Successful Message response as aboveCompare returned chat/topic with the intended destinationRecord message_id; do not infer a read receipt

An empty webhook URL does not prove polling is healthy, and a historical last_error_message does not by itself prove a current outage. Compare timestamps and the new test event. A timeout without a definitive response remains unknown: it is not the same as the explicit 403 or 429 rejection above.

Start with the symptom, not the deployment

Find the first missing observation
SymptomInspect firstWhat it separates
No command reaches your logsBot identity, update transport and configured update typesReceiving updates from executing the command
The update is logged but there is no reply attemptHandler state, exceptions, queue and dependenciesApplication processing from Telegram delivery
The outgoing request returns an errorHTTP status, Bot API error and response parametersA rejected request from a local timeout
API success is recorded but the user sees nothingReturned chat and message identifiers, topic and notification expectationsAPI acceptance from reading or receiving a notification
Some messages arrive twiceUpdate identity, business operation and outgoing attemptsRepeated input from repeated side effects

1. Confirm the bot and the destination

Call getMe from your secured application environment to confirm which bot the configured token identifies. Compare that identity with the bot the tester actually opened. A valid token for a staging bot can produce successful API responses while the operator is watching the production chat. Do not paste a token-bearing Bot API URL into a support ticket, screenshot or analytics log.

For a private-chat test, have the participant open the intended bot and send /start. A bot cannot initiate an arbitrary private conversation with a user who has not contacted it. For a group, channel or forum topic, verify the actual chat identity, membership, required permissions and any message_thread_id your workflow supplies. Do not copy a chat identifier from an unrelated environment.

2. Check webhook or long polling without discarding updates

Use getWebhookInfo to see whether a webhook URL is configured. Inspect pending_update_count and, when present, last_error_date and last_error_message. A rising pending count combined with a delivery error is useful evidence; a zero count alone does not prove that your handler executed successfully. Compare the timestamps with the test event.

getUpdates does not work while an outgoing webhook is configured. Decide which transport this deployment is supposed to use, then check that transport. For polling, look for competing consumers and whether the offset is advanced after the intended processing boundary. For a webhook, check endpoint reachability, the expected route, its response status and your validation of the configured secret header.

Choose transport to fit the host, then diagnose it
Deployment conditionReasonable starting pointStill required
A persistent worker with outbound connectivityLong polling may be appropriateConsumer coordination, offset policy and restart recovery
A stable public HTTPS endpointA webhook may be appropriateRequest validation, durable intake and timely responses
Long AI or third-party processingEither transport with durable queued workRecord intake before acknowledgement; process expensive work separately
A host that sleeps or restarts frequentlyEvaluate the host lifecycle before choosingA recovery policy for work left in progress

Long polling is not inherently a slow periodic check: the server can hold the request until an update is available. Switching to webhooks is therefore not a universal latency fix. Likewise, deleting a webhook, changing the polling offset or using drop_pending_updates can lose work. Make those changes only with a deliberate migration or discard policy, not as a troubleshooting ritual.

3. Trace one update through the application

Create one known test event and follow its update_id through intake, handler selection, validation, queue and outgoing request. Check whether allowed_updates excludes the event type you expect. In groups, privacy mode and the type of message also affect which updates a bot receives; use a supported command addressed to the bot before concluding that transport is broken.

An HTTP success from your webhook endpoint can acknowledge an update even if later application work fails. If the handler starts a slow AI call and then crashes, Telegram transport may be healthy while your own workflow has lost the job. Record a durable work item and observable processing state rather than relying on a single line saying that the webhook returned 200.

4. Try one plain-text reply and inspect the response

Send a short plain-text test through the same application connection and intended test chat, initially without parse_mode, media or optional formatting. This isolates chat access and basic sending from entity parsing, file retrieval and template construction. Then add the failing option back one at a time. A successful minimal test does not validate the original message payload.

Classify the actual result before choosing recovery
ResultUseful evidenceNext action
Successful Message responseReturned chat identity and message_idRecord acceptance; inspect the intended destination and topic
Bad request or permission errorExact description and failed operationCorrect the payload or access; do not blindly repeat the same request
Flood controlretry_after when returnedWait at least the specified interval and revalidate queued work
Connection timeout without a definitive resultAttempt identity, timestamps and available transport evidenceMark uncertain; decide whether and how to reconcile before another send
Application never attempted sendMessageLast completed stage and dependency errorRepair processing; changing Telegram permissions will not fix the missing attempt

A successful Bot API response is not a read receipt and does not promise a notification on the user's device. Muted chats, the wrong destination or a forum topic can explain the difference. Do not rotate a working token or resend a real notification solely because the tester did not see a push alert.

5. If replies are duplicated, identify which operation repeated

Two incoming records with the same update_id suggest repeated intake. Two different updates may represent two separate user actions. One recorded operation with two outgoing attempts points to retry or worker coordination. These cases need different fixes. A durable unique operation identity and an atomic claim help inside your application, but they cannot make Telegram and your database one transaction.

After a timeout, Telegram may already have accepted a message. Retrying without a confirmed failure can duplicate it. Keep an uncertain state and choose the tradeoff for the product: an operator review may be appropriate for an important notification, while a routine digest can have a documented skip policy. Do not promise exactly-once external delivery from a local deduplication key.

Keep a diagnostic record that another person can use

Sanitized incident record — illustrative fields
observed_at_utc | environment | bot_alias | transport
update_id | operation_id | stage | attempt_number
http_status | api_error_category | retry_after_seconds
message_id_if_confirmed | outcome | next_action

Exclude: tokens, secret headers, full private messages and unnecessary user identifiers.

Finish with a controlled retest: one incoming command, one application operation, one intended outgoing action and a recorded outcome. Then test a restart, repeated intake and a temporary dependency failure separately. Keep the original evidence so a later intermittent incident can be compared with the same stage boundaries.

Built from the work.WeMAIde designs and ships AI software, apps, Telegram products and automation systems.

FROM THINKING TO PRODUCT

Need something like this built?

Tell us what needs to work. We will come back with the clearest next step.

Discuss it in Telegram ↗