I am working on a simple Telegram bot using python-telegram-bot library. The bot includes a button which, upon being clicked, should make an HTTP request and display the response data without opening a browser. Here’s my current code:
import requests
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import CallbackContext
from telegram.constants import ParseMode
def fetch_data():
response = requests.get('https://jsonplaceholder.typicode.com/comments/1')
return response.json()['body']
def start(update: Update, context: CallbackContext) -> None:
buttons = [
[InlineKeyboardButton('Get data', callback_data=fetch_data())]
]
reply_markup = InlineKeyboardMarkup(buttons)
update.message.reply_text('Choose an option:', reply_markup=reply_markup)
def button(update: Update, context: CallbackContext) -> None:
query = update.callback_query
query.answer()
content = f"<h3>{query.data}</h3>"
query.edit_message_text(text=content, parse_mode=ParseMode.HTML)
This code works fine for static data and text shorter than 50 characters. But when the text exceeds 80 characters, I get this error:
telegram.error.BadRequest: Button_data_invalid
Is this a Telegram API limitation (64-byte text limit)? How do some bots display messages with thousands of characters? What am I missing?
I’ve dealt with this issue before, and it’s definitely related to the 64-byte limit for callback_data. Here’s what worked for me:
Instead of passing the entire data through the button, I used a unique identifier and stored the actual data server-side. My approach was to use Redis as a temporary cache, but you could also use a database or even a simple dictionary in memory (though this isn’t ideal for production).
Here’s a quick example of how I modified the code:
import uuid
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
# Assuming you have a cache or database set up
cache = {}
def start(update, context):
data_id = str(uuid.uuid4())
cache[data_id] = fetch_data()
button = InlineKeyboardButton('Get data', callback_data=f'get:{data_id}')
update.message.reply_text('Choose:', reply_markup=InlineKeyboardMarkup([[button]]))
def button(update, context):
query = update.callback_query
action, data_id = query.data.split(':')
if action == 'get':
data = cache.get(data_id, 'Data not found')
query.edit_message_text(text=data)
query.answer()
This way, you’re only passing a short identifier in the callback_data, staying well within the 64-byte limit. When the button is clicked, you fetch the full data using this identifier. It’s worked great for me, even with very large responses.
hey mate, i had a similar issue. store large text in bot_data and pass a short id in callback_data. for example:
def start(u,c):
c.bot_data['d']=fetch_data()
u.message.reply_text('choose', reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton('data', callback_data='id')]]))
def button(u,c):
u.callback_query.edit_message_text(c.bot_data['d'])
this way you avoid the 64-byte limit. hope it helps!