Telegram error 400: Bad Request: message is not modified
Last verified against Telegram Bot API reference
Bad Request: message is not modified: specified new message content and reply markup are exactly the same as a current content and reply markup of the messageWhat error 400 means
You asked Telegram to edit a message, and the new text, entities and reply markup are byte-for-byte identical to what the message already contains. Telegram rejects no-op edits rather than silently accepting them, and returns the long description above. In practice the shorter prefix message is not modified is what most libraries match on.
This is the most harmless 400 in the whole API and also the noisiest. Menu bots that re-render an inline keyboard on every callback, pagination that lands on the same page, and 'refresh' buttons all trigger it constantly. Nothing is broken; the user simply sees no change, which is what they would have seen anyway.
Where it becomes a real bug is when your code treats any 400 as fatal and aborts the handler, so the answerCallbackQuery that should follow never runs and the user's button spinner hangs until the query expires with query is too old.
Library behavior differs enough to matter here. python-telegram-bot raises telegram.error.BadRequest; the common idiom is to catch it and check for "Message is not modified" in the message string. aiogram v3 raises TelegramBadRequest, matched the same way. grammY and Telegraf hand you the description on the error object (err.description), and node-telegram-bot-api on error.response.body.description. Comparison is against the parsed result, so two different markup strings that produce identical entities (say, the same bold text written in HTML and MarkdownV2) still count as 'not modified'.
Reproducing it takes one button: send a message with an inline keyboard whose handler edits the message to the same text, tap it twice, and the second tap fails with this description. That determinism is also what makes it safe to suppress: the failure carries no information beyond 'nothing changed', so treating it as success never hides a real fault.
What it looks like
{"ok":false,"error_code":400,"description":"Bad Request: message is not modified: specified new message content and reply markup are exactly the same as a current content and reply markup of the message"}Why it happens
- A callback handler redraws the same menu without checking whether state changed.
- Pagination or 'refresh' logic re-sends identical content.
- Two rapid taps on the same button produce two identical edits; the second one fails.
- Formatting differences you expected (e.g. Markdown vs HTML) collapse to the same entities after parsing.
How to fix Telegram error 400
- 1Catch this description specifically and treat it as success.
- 2Always call
answerCallbackQueryregardless of whether the edit succeeded, so the client stops its loading state. - 3Compare your intended text and markup with the last-rendered version before calling edit; skip when equal.
- 4Debounce repeated taps on the same callback_data within a short window.
- 5For 'refresh' buttons, add a changing element (a timestamp in the text) or answer the callback with a 'no changes' toast instead of editing.
How to stop it recurring
Keep a hash of the last rendered content per message and short-circuit identical renders. Structure callback handling as 'answer first, edit second', so UI feedback never depends on the edit result. Exclude this description from error alerting; it is noise, not a fault. The related editing rules (what a bot may edit, and the 48-hour rule for business messages) are collected under editing and deleting limits.
Official reference: Telegram Bot API reference. See all Telegram error codes or the Telegram limits and quotas.
Related codes
- 400: Bad Request: message can't be editedBad Request: message can't be edited
- 400: Bad Request: query is too old and response timeout expired or query ID is invalidBad Request: query is too old and response timeout expired or query ID is…
- 400: Bad Request: message not foundBad Request: message not found
Error 400 - quick answers
What does Telegram error 400 mean?
You asked Telegram to edit a message, and the new text, entities and reply markup are byte-for-byte identical to what the message already contains. Telegram rejects no-op edits rather than silently accepting them, and returns the long description above. In practice the shorter prefix message is not modified is what most libraries match on. This is the most harmless 400 in the whole API and also the noisiest.
How do I fix Telegram error 400?
1. Catch this description specifically and treat it as success. 2. Always call answerCallbackQuery regardless of whether the edit succeeded, so the client stops its loading state. 3. Compare your intended text and markup with the last-rendered version before calling edit; skip when equal. 4. Debounce repeated taps on the same callback_data within a short window. 5. For 'refresh' buttons, add a changing element (a timestamp in the text) or answer the callback with a 'no…
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.