Telegram error 400: Bad Request: message to delete not found
Last verified against Telegram Bot API reference
Bad Request: message to delete not foundWhat error 400 means
deleteMessage (or deleteMessages) was called with a message that is not there to delete. Either it was already removed, it never existed with that ID in that chat, or it is older than the bot's visibility window. The bot succeeded in authenticating and the chat is valid, so this is a state problem, not a configuration problem.
In most bots this error is benign: a user deleted their own message, an admin cleaned the chat, or two code paths both try to delete the same message (a 'delete on timeout' job and a 'delete on answer' job). Only the first one wins. Reproducing it is trivial: send a message, delete it from the client by hand, then let your cleanup job call deleteMessage for it.
If you are trying to delete a message your bot should be able to see and it was sent recently, suspect an ID mix-up rather than anything Telegram-side. Deleting requires the exact (chat_id, message_id) pair, and message IDs are scoped per chat; after a group migrates to a supergroup, old message IDs do not carry over to the new -100... chat (see the migration error).
python-telegram-bot raises telegram.error.BadRequest with this description, and aiogram v3 raises TelegramBadRequest; in both, the standard pattern is a small wrapper that catches the exception, checks the description for message to delete not found, and returns as if the delete succeeded. Telegraf, grammY and node-telegram-bot-api expose the description on the error object for the same check. Contrast with message can't be deleted, where the message exists but policy (age or rights) forbids removing it.
What it looks like
{"ok":false,"error_code":400,"description":"Bad Request: message to delete not found"}Why it happens
- Double delete: two handlers (timeout cleanup, callback handler, admin command) race to remove the same message.
- The message was deleted by a user or another bot first.
- The message_id belongs to a different chat, typically after a group-to-supergroup migration.
- The message is in a channel where the bot only recently gained
can_post_messagesand never received the original. - A stored message_id was overwritten or reset by a deploy, so the job deletes an ID that never existed.
How to fix Telegram error 400
- 1Make delete idempotent in your code: catch this description and return success.
- 2Record the deletion in your own state so later jobs skip the call.
- 3Confirm you are deleting in the same chat the message was sent in; check for
migrate_to_chat_idin recent updates. - 4Use
deleteMessages(the batch form) for cleanups; it tolerates the set changing under you better than a loop of single deletes. - 5If the message is older than 48 hours, note that bots cannot delete it anyway; you will see
message can't be deletedinstead.
How to stop it recurring
Route all deletes through one function that swallows this error and updates local state. Use deleteMessages for batches so that a single missing ID does not require per-message error handling. Keep a short TTL on scheduled deletions and re-check existence for anything scheduled far ahead. The 48-hour deletion window and its documented exceptions are listed under editing and deleting limits.
Official reference: Telegram Bot API reference. See all Telegram error codes or the Telegram limits and quotas.
Related codes
Error 400 - quick answers
What does Telegram error 400 mean?
deleteMessage (or deleteMessages ) was called with a message that is not there to delete. Either it was already removed, it never existed with that ID in that chat, or it is older than the bot's visibility window. The bot succeeded in authenticating and the chat is valid, so this is a state problem, not a configuration problem.
How do I fix Telegram error 400?
1. Make delete idempotent in your code: catch this description and return success. 2. Record the deletion in your own state so later jobs skip the call. 3. Confirm you are deleting in the same chat the message was sent in; check for migrate_to_chat_id in recent updates. 4. Use deleteMessages (the batch form) for cleanups; it tolerates the set changing under you better than a loop of single deletes. 5. If the message is older than 48 hours, note that bots cannot delete it…
Should I retry after error 400?
No. Retrying the same request produces the same error; the condition has to be fixed first. Treat it as a permanent failure for that message and surface it, rather than looping.
Stop debugging Telegram by hand
Connect the channel through Conferbot: tokens, webhooks and retries are handled, failures show as readable status.