Telegram error 400: Bad Request: BUTTON_DATA_INVALID
Last verified against Telegram Bot API reference
Bad Request: BUTTON_DATA_INVALIDWhat error 400 means
An inline keyboard button's callback_data does not meet the Bot API rule: 1 to 64 bytes. Exceeding 64 bytes, or sending an empty string, triggers this raw server error and rejects the whole message or edit. The limit is in bytes, so 64 characters of non-ASCII text can be far more than 64 bytes.
Developers hit this when they try to pack meaningful state into the button: a JSON object, a UUID plus an action, a product name, or a serialized filter. Telegram intends callback_data to be a short key, not a payload.
Nothing is wrong with the message text itself, and the chat is fine. Fix the keyboard and resend.
What it looks like
{"ok":false,"error_code":400,"description":"Bad Request: BUTTON_DATA_INVALID"}Why it happens
- Serialized JSON or multiple IDs concatenated into callback_data.
- UUIDs (36 chars) combined with prefixes and separators exceeding 64 bytes.
- Multi-byte characters pushing a 'short' string over the byte limit.
- An empty callback_data from a template branch.
How to fix Telegram error 400
- 1Measure
len(callback_data.encode('utf-8'))for every button; keep it at or below 64. - 2Store state server-side and put only a short opaque key (for example
a:123) in the button. - 3Use compact encodings (base64url of binary IDs) when you must carry more than one field.
- 4Add a validation step in your keyboard builder that fails loudly in development.
- 5If you edited an existing keyboard, note that every button in the new markup is validated, not only the one you changed.
How to stop it recurring
Treat callback_data as a lookup key. A small table mapping keys to action payloads keeps buttons tiny and lets you change behaviour without resending keyboards. Enforce the 64-byte rule in one shared function, and include a test that builds your largest real keyboard and asserts every button passes. Keep prefixes short (one or two characters) so the remaining bytes are available for identifiers.
The byte budget and its neighbors (copy_text 1-256 characters, callback answer text 0-200 characters) are tabulated under keyboard and callback limits. When the URL field rather than the data field is the problem, the API answers with BUTTON_URL_INVALID instead.
Official reference: Telegram Bot API reference. See all Telegram error codes or the Telegram limits and quotas.
Related codes
- 400: Bad Request: BUTTON_URL_INVALIDBad Request: BUTTON_URL_INVALID
- 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 is not modifiedBad Request: message is not modified: specified new message content and reply…
Error 400 - quick answers
What does Telegram error 400 mean?
An inline keyboard button's callback_data does not meet the Bot API rule: 1 to 64 bytes. Exceeding 64 bytes, or sending an empty string, triggers this raw server error and rejects the whole message or edit. The limit is in bytes , so 64 characters of non-ASCII text can be far more than 64 bytes.
How do I fix Telegram error 400?
1. Measure len(callback_data.encode('utf-8')) for every button; keep it at or below 64. 2. Store state server-side and put only a short opaque key (for example a:123 ) in the button. 3. Use compact encodings (base64url of binary IDs) when you must carry more than one field. 4. Add a validation step in your keyboard builder that fails loudly in development. 5. If you edited an existing keyboard, note that every button in the new markup is validated, not only the one you…
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.