pythonpython-requeststelegramtelegram-botpython-telegram-bot

Python Telegram API raises unhelpful error when trying to edit message media


I'm programming a telegram bot in python that, on command, starts sending a photo of a window on my computer to the chat every few seconds. Of course I don't want the chat to get spammed with photos so instead I want to go back and edit the first message that I send using edit_media.

Currently my callback function to the command looks like this:

def callback(update: Update, context: CallbackContext):
    first = True
    while True:
        image = screenshot('Snake')     # Gets a screenshot of the window
        bytesio = io.BytesIO()
        image.save(bytesio, format='PNG')
        bytes_image = bytes(bytesio.getvalue())     # Convert to bytes object
        if first:       # First time send a full message 
            context.bot.send_photo(update.message.chat_id, bytes_image)
            first = False
        else:       
            update.message.edit_media(media=InputMediaPhoto(media=bytes_image)) # Edit the message with the next photo
        time.sleep(2)

When this function runs, the first message is sent successfully, but trying to edit the message raises an error: telegram.error.BadRequest: Message can't be edited

How do I solve this so that the image is successfully edited?

The full traceback of the error is:

Traceback (most recent call last):
  File "C:\Users\...\telegram\ext\dispatcher.py", line 555, in process_update
    handler.handle_update(update, self, check, context)
  File "C:\Users\...\telegram\ext\handler.py", line 198, in handle_update
    return self.callback(update, context)
  File "C:\Users\...\TelegramGameHub\main.py", line 56, in snake
    update.message.edit_media(media=InputMediaPhoto(media=bytes_image))
  File "C:\Users\...\telegram\message.py", line 2016, in edit_media
    return self.bot.edit_message_media(
  File "C:\Users\...\telegram\bot.py", line 130, in decorator
    result = func(*args, **kwargs)
  File "C:\Users\...\telegram\bot.py", line 2723, in edit_message_media
    return self._message(
  File "C:\Users\...\telegram\ext\extbot.py", line 199, in _message
    result = super()._message(
  File "C:\Users\...\telegram\bot.py", line 332, in _message
    result = self._post(endpoint, data, timeout=timeout, api_kwargs=api_kwargs)
  File "C:\Users\...\telegram\bot.py", line 295, in _post
    return self.request.post(
  File "C:\Users\...\telegram\utils\request.py", line 354, in post
    result = self._request_wrapper('POST', url, fields=data, **urlopen_kwargs)
  File "C:\Users\...\telegram\utils\request.py", line 279, in _request_wrapper
    raise BadRequest(message)

Solution

  • The problem is that your line

    update.message.edit_media(media=InputMediaPhoto(media=bytes_image))
    

    doesn't edit the photo message that you sent. It instead tries to edit the message that initially triggered the callback.

    To get a hold of the message that you send, you'll need to do something like

    message = context.bot.send_photo(update.message.chat_id, bytes_image)
    

    Note that PTB provides shortcuts for these kind of things. So you could abbreviate this to

    message = update.message.reply_photo(bytes_image)
    

    which is (almost) equivalent.

    Now you can call message.edit_media(...) to update the photo.

    Another thing to note is that your loop

    while True:
       ...
       time.sleep(2)
    

    is blocking. That means that after entering the function callback, your bot won't process any other updates. (Side note in case you know what run_async does: Even if you run this callback asynchronously, it will block one of the worker threads and as soon as enough updates have triggered this callback, all the worker threads are blocked and your bot won't process any more updates)

    I highly recommend to use the built in JobQueue for such things. See also the wiki page and the example.


    Disclaimer: I'm currently the maintainer of python-telegram-bot.