python-telegram-bot/python-telegram-bot · error · ValueError

Message and chat_id pair are mutually exclusive

Error message

Message and chat_id pair are mutually exclusive

What it means

Application.migrate_chat_data() accepts either a `message` (a service message about migration) or the `old_chat_id`/`new_chat_id` pair — not both. Passing message together with either chat id raises ValueError.

Source

Thrown at src/telegram/ext/_application.py:1572

            message (:class:`telegram.Message`, optional): A message with either
                :attr:`~telegram.Message.migrate_from_chat_id` or
                :attr:`~telegram.Message.migrate_to_chat_id`.
                Mutually exclusive with passing :paramref:`old_chat_id` and
                :paramref:`new_chat_id`.

                .. seealso::
                    :attr:`telegram.ext.filters.StatusUpdate.MIGRATE`

            old_chat_id (:obj:`int`, optional): The old chat ID.
                Mutually exclusive with passing :paramref:`message`
            new_chat_id (:obj:`int`, optional): The new chat ID.
                Mutually exclusive with passing :paramref:`message`

        Raises:
            ValueError: Raised if the input is invalid.
        """
        if message and (old_chat_id or new_chat_id):
            raise ValueError("Message and chat_id pair are mutually exclusive")
        if not any((message, old_chat_id, new_chat_id)):
            raise ValueError("chat_id pair or message must be passed")

        if message:
            if message.migrate_from_chat_id is None and message.migrate_to_chat_id is None:
                raise ValueError(
                    "Invalid message instance. The message must have either "
                    "`Message.migrate_from_chat_id` or `Message.migrate_to_chat_id`."
                )

            old_chat_id = message.migrate_from_chat_id or message.chat.id
            new_chat_id = message.migrate_to_chat_id or message.chat.id

        elif not (isinstance(old_chat_id, int) and isinstance(new_chat_id, int)):
            raise ValueError("old_chat_id and new_chat_id must be integers")

        self._chat_data[new_chat_id] = self._chat_data[old_chat_id]
        self.drop_chat_data(old_chat_id)

View on GitHub (pinned to d3b69d2e9f)

Solutions

  1. Pass only `message` and let the ids be extracted from it
  2. Or pass only the `old_chat_id`/`new_chat_id` pair without message

Example fix

# before
await app.migrate_chat_data(message=msg, old_chat_id=old, new_chat_id=new)

# after
await app.migrate_chat_data(message=msg)
Defensive patterns

Strategy: validation

Validate before calling

if message and (old_chat_id or new_chat_id):
    raise ValueError('pass either message or the id pair, not both')

Prevention

When it happens

Trigger: `app.migrate_chat_data(message=msg, old_chat_id=-100, new_chat_id=-200)`; also message plus only one of the ids triggers it because the check is `message and (old_chat_id or new_chat_id)`.

Common situations: Custom on_chat_migration logic copying docs and filling every parameter; generic wrapper code that passes all kwargs through.

Related errors


AI-assisted analysis of python-telegram-bot/python-telegram-bot@d3b69d2e9f (2026-08-28). Data as JSON: /api/errors/30c199e5a41de9ee. Report an issue: GitHub.