Telegram Bot API errors, one by one
Last verified against Telegram Bot API reference
Telegram does not publish a numbered error table the way WhatsApp or Discord do. A failed Bot API call returns an HTTP status in error_code and a short, literal description string, and the documentation explicitly says the numeric code is subject to change. In practice the description is stable and it is what developers search for, so this page is organized by description: one entry per distinct string, grouped under the status that carries it. Where a description varies (a byte offset, a retry time, the chat type the bot was kicked from) the stable prefix is listed and the variable part is marked.
Errors come back in the response body of the method you called. Webhook delivery failures are different: those surface in getWebhookInfo as last_error_message, not as a response to your request, and are covered in Telegram bot not responding and the webhook debugging guide. Two errors also carry a machine-readable parameters object (the ResponseParameters type): 429 includes retry_after (seconds to wait) and the supergroup migration error includes migrate_to_chat_id (the replacement chat ID). Log the full body, not just the status; Telegram's descriptions are short but precise.
Client libraries wrap these responses in their own exception types: python-telegram-bot raises Conflict, Forbidden, RetryAfter or ChatMigrated; aiogram raises TelegramConflictError, TelegramForbiddenError, TelegramRetryAfter or TelegramMigrateToChat; Telegraf and grammY throw error objects carrying error_code, description and parameters; node-telegram-bot-api prefixes messages with ETELEGRAM. Each entry below names the wrapper where it helps you search. Every string was checked against the Bot API reference and FAQ and against the literal matchers used by the major client libraries. Status-only entries (502, 504) come from Telegram's front-end proxy and return HTML rather than JSON. Related: Telegram Bot API limits and the bot token checker.
How to read a Telegram error
Every Bot API response is a JSON object with a Boolean ok. On failure, ok is false, error_code repeats the HTTP status (the docs say its contents are subject to change), and description carries the human-readable string this page is indexed by. Some errors add a parameters object of type ResponseParameters with up to two fields: retry_after, 'the number of seconds left to wait before the request can be repeated' after flood control, and migrate_to_chat_id, the supergroup ID that replaced a migrated group (up to 52 significant bits, so store it in a 64-bit integer). The three shapes:
{
"ok": false,
"error_code": 409,
"description": "Conflict: terminated by other getUpdates request; make sure that only one bot instance is running"
}
{
"ok": false,
"error_code": 429,
"description": "Too Many Requests: retry after 34",
"parameters": { "retry_after": 34 }
}
{
"ok": false,
"error_code": 400,
"description": "Bad Request: group chat was upgraded to a supergroup chat",
"parameters": { "migrate_to_chat_id": -1001234567890 }
}All 40 codes
Jump to: 400 Bad Request: identifiers, content and rights (19) · 400 Bad Request: files and media (5) · 400 Bad Request: webhook registration (3) · 401 / 404: token and path (2) · 403 Forbidden: blocked, kicked, not started (6) · 409 Conflict: getUpdates and webhooks (2) · 429 Too Many Requests (1) · 502 / 504: Telegram-side (2)
400 Bad Request: identifiers, content and rights
| Code | Title |
|---|---|
400 | Bad Request: chat not found Bad Request: chat not found |
400 | Bad Request: user not found Bad Request: user not found |
400 | Bad Request: message not found Bad Request: message not found |
400 | Bad Request: message to delete not found Bad Request: message to delete not found |
400 | Bad Request: message can't be deleted Bad Request: message can't be deleted |
400 | Bad Request: message can't be edited Bad Request: message can't be edited |
400 | Bad Request: message is not modified Bad Request: message is not modified: specified new message content and reply markup are exactly the same as a curren… |
400 | Bad Request: can't parse entities Bad Request: can't parse entities: <detail varies> |
400 | Bad Request: message text is empty Bad Request: message text is empty |
400 | Bad Request: message is too long Bad Request: message is too long |
400 | Bad Request: message to be replied not found Bad Request: message to be replied not found |
400 | Bad Request: chat_id is empty Bad Request: chat_id is empty |
400 | Bad Request: have no rights to send a message Bad Request: have no rights to send a message |
400 | Bad Request: not enough rights to send text messages to the chat Bad Request: not enough rights to send text messages to the chat |
400 | Bad Request: CHAT_WRITE_FORBIDDEN Bad Request: CHAT_WRITE_FORBIDDEN |
400 | Bad Request: group chat was upgraded to a supergroup chat Bad Request: group chat was upgraded to a supergroup chat |
400 | Bad Request: query is too old and response timeout expired or query ID is invalid Bad Request: query is too old and response timeout expired or query ID is invalid |
400 | Bad Request: BUTTON_URL_INVALID Bad Request: BUTTON_URL_INVALID |
400 | Bad Request: BUTTON_DATA_INVALID Bad Request: BUTTON_DATA_INVALID |
400 Bad Request: files and media
| Code | Title |
|---|---|
400 | Bad Request: wrong file identifier/HTTP URL specified Bad Request: wrong file identifier/HTTP URL specified |
400 | Bad Request: wrong remote file identifier specified Bad Request: wrong remote file identifier specified: <detail varies> |
400 | Bad Request: file is too big Bad Request: file is too big |
400 | Bad Request: PHOTO_INVALID_DIMENSIONS Bad Request: PHOTO_INVALID_DIMENSIONS |
400 | Bad Request: failed to get HTTP URL content Bad Request: failed to get HTTP URL content |
400 Bad Request: webhook registration
| Code | Title |
|---|---|
400 | Bad Request: bad webhook: HTTPS url must be provided for webhook Bad Request: bad webhook: HTTPS url must be provided for webhook |
400 | Bad Request: bad webhook: Webhook can be set up only on ports 80, 88, 443 or 8443 Bad Request: bad webhook: Webhook can be set up only on ports 80, 88, 443 or 8443 |
400 | Bad Request: bad webhook: failed to resolve host Bad Request: bad webhook: failed to resolve host: <detail varies> |
401 / 404: token and path
| Code | Title |
|---|---|
401 | Unauthorized Unauthorized |
404 | Not Found Not Found |
403 Forbidden: blocked, kicked, not started
| Code | Title |
|---|---|
403 | Forbidden: bot was blocked by the user Forbidden: bot was blocked by the user |
403 | Forbidden: bot was kicked from the group chat Forbidden: bot was kicked from the group chat |
403 | Forbidden: bot can't initiate conversation with a user Forbidden: bot can't initiate conversation with a user |
403 | Forbidden: user is deactivated Forbidden: user is deactivated |
403 | Forbidden: bot is not a member of the channel chat Forbidden: bot is not a member of the channel chat |
403 | Forbidden: bot can't send messages to bots Forbidden: bot can't send messages to bots |
409 Conflict: getUpdates and webhooks
| Code | Title |
|---|---|
409 | Conflict: terminated by other getUpdates request Conflict: terminated by other getUpdates request; make sure that only one bot instance is running |
409 | Conflict: can't use getUpdates method while webhook is active Conflict: can't use getUpdates method while webhook is active; use deleteWebhook to delete the webhook first |
429 Too Many Requests
| Code | Title |
|---|---|
429 | Too Many Requests: retry after N Too Many Requests: retry after 34 |
502 / 504: Telegram-side
| Code | Title |
|---|---|
502 | 502 Bad Gateway 502 Bad Gateway (HTML body from the api.telegram.org front end; not a JSON Bot API response) |
504 | 504 Gateway Timeout 504 Gateway Timeout (HTML body from the api.telegram.org front end; not a JSON Bot API response) |
Telegram guides and tools
Other platforms
Frequently asked questions
Why doesn't Telegram have numeric error codes like WhatsApp or Discord?
The Bot API returns the HTTP status in error_code and a human-readable description, and the documentation states the numeric code is subject to change. The description string is the stable part and is what client libraries match on. This page is therefore indexed by description rather than by a code table.
What does 'Conflict: terminated by other getUpdates request' mean?
Two processes are long-polling getUpdates with the same bot token. Telegram allows one poller per token, terminates the older connection, and each instance then receives only some updates. Stop every extra instance (local shells, extra replicas, old deploys) or switch to webhooks behind a load balancer.
How do I fix 'can't use getUpdates method while webhook is active'?
A webhook is registered on the token. Call getWebhookInfo to see it, then deleteWebhook (optionally with drop_pending_updates=true) before polling. Webhooks and getUpdates are mutually exclusive per the Bot API documentation.
What is the difference between 'bot was blocked by the user' and 'bot can't initiate conversation with a user'?
Blocked means the user started your bot and then blocked it; stop sending until they return. Can't initiate means the user has never started your bot; a bot may not message anyone first, so they must send /start or tap a deep link before you can write to them.
How should I handle 429 'Too Many Requests: retry after N'?
Read parameters.retry_after and wait exactly that many seconds before retrying. Keep sends under roughly one message per second per chat, 20 per minute per group and about 30 per second overall, as the FAQ describes. Paid Broadcasts in @BotFather raise the bulk limit to 1000 per second for a fee in Stars.
Why do I get 'chat not found' for a user ID I know is correct?
A bot can only address chats it has already seen. If the user never pressed Start, or the ID came from another bot, another system, or was truncated to 32 bits, Telegram cannot resolve it for this bot. For groups, check whether the chat was upgraded to a supergroup and now has a -100 prefixed ID.
What does 'can't parse entities' mean and how do I avoid it?
Your text does not parse under the parse_mode you set. MarkdownV2 requires escaping many punctuation characters; HTML allows only a small tag set and needs & < > escaped. Escape all interpolated content, or send plain text with an entities array. The byte offset in the description points at the failure.
Is a 502 or 504 from api.telegram.org my fault?
No. Those come from Telegram's front-end proxy and usually carry an HTML body rather than the JSON error object. Retry with backoff, guard your JSON parsing, and for sends consider whether a retry could duplicate a message that actually went through.
What is the parameters object (retry_after, migrate_to_chat_id) in a Telegram error?
Some errors include a ResponseParameters object alongside the description. retry_after appears on 429 responses and is the number of seconds to wait before repeating the request. migrate_to_chat_id appears when a group was upgraded to a supergroup and holds the replacement chat ID, which can exceed 32 bits, so store it as a 64-bit integer. Always decode parameters, not just the description.
Why does my library show TelegramConflictError or ETELEGRAM instead of a Telegram error code?
Client libraries wrap the raw JSON in their own exception types. python-telegram-bot raises Conflict, Forbidden, RetryAfter, ChatMigrated or InvalidToken; aiogram raises TelegramConflictError, TelegramForbiddenError, TelegramRetryAfter or TelegramMigrateToChat; Telegraf and grammY throw errors carrying error_code, description and parameters; node-telegram-bot-api prefixes messages with ETELEGRAM. The underlying description string is identical across all of them.
Run your Telegram bot without babysitting error codes
Conferbot manages the connection, tokens, webhooks and retries, and shows failures as readable status.