Hide navigation sidebar
Hide table of contents sidebar
PTB has undergone significant changes in v20. Please read the documentation carefully and also check out the transition guide in the wiki.
Back to top
Toggle table of contents sidebar

# `errorhandlerbot.py`

     1#!/usr/bin/env python
     2# pylint: disable=unused-argument
     3# This program is dedicated to the public domain under the CC0 license.
     4
     5"""This is a very simple example on how one could implement a custom error handler."""
     6import html
     7import json
     8import logging
     9import traceback
    10
    11from telegram import Update
    12from telegram.constants import ParseMode
    13from telegram.ext import Application, CommandHandler, ContextTypes
    14
    15# Enable logging
    16logging.basicConfig(
    17    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
    18)
    19# set higher logging level for httpx to avoid all GET and POST requests being logged
    20logging.getLogger("httpx").setLevel(logging.WARNING)
    21
    22logger = logging.getLogger(__name__)
    23
    24# This can be your own ID, or one for a developer group/channel.
    25# You can use the /start command of this bot to see your chat id.
    26DEVELOPER_CHAT_ID = 123456789
    27
    28
    29async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE) -> None:
    30    """Log the error and send a telegram message to notify the developer."""
    31    # Log the error before we do anything else, so we can see it even if something breaks.
    32    logger.error("Exception while handling an update:", exc_info=context.error)
    33
    34    # traceback.format_exception returns the usual python message about an exception, but as a
    35    # list of strings rather than a single string, so we have to join them together.
    36    tb_list = traceback.format_exception(None, context.error, context.error.__traceback__)
    37    tb_string = "".join(tb_list)
    38
    39    # Build the message with some markup and additional information about what happened.
    40    # You might need to add some logic to deal with messages longer than the 4096 character limit.
    41    update_str = update.to_dict() if isinstance(update, Update) else str(update)
    42    message = (
    43        "An exception was raised while handling an update\n"
    44        f"<pre>update = {html.escape(json.dumps(update_str, indent=2, ensure_ascii=False))}"
    45        "</pre>\n\n"
    46        f"<pre>context.chat_data = {html.escape(str(context.chat_data))}</pre>\n\n"
    47        f"<pre>context.user_data = {html.escape(str(context.user_data))}</pre>\n\n"
    48        f"<pre>{html.escape(tb_string)}</pre>"
    49    )
    50
    51    # Finally, send the message
    52    await context.bot.send_message(
    53        chat_id=DEVELOPER_CHAT_ID, text=message, parse_mode=ParseMode.HTML
    54    )
    55
    56
    57async def bad_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    58    """Raise an error to trigger the error handler."""
    59    await context.bot.wrong_method_name()  # type: ignore[attr-defined]
    60
    61
    62async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    63    """Displays info on how to trigger an error."""
    64    await update.effective_message.reply_html(
    65        "Use /bad_command to cause an error.\n"
    66        f"Your chat id is <code>{update.effective_chat.id}</code>."
    67    )
    68
    69
    70def main() -> None:
    71    """Run the bot."""
    72    # Create the Application and pass it your bot's token.
    73    application = Application.builder().token("TOKEN").build()
    74
    75    # Register the commands...
    76    application.add_handler(CommandHandler("start", start))
    77    application.add_handler(CommandHandler("bad_command", bad_command))
    78
    79    # ...and the error handler
    80    application.add_error_handler(error_handler)
    81
    82    # Run the bot until the user presses Ctrl-C
    83    application.run_polling(allowed_updates=Update.ALL_TYPES)
    84
    85
    86if __name__ == "__main__":
    87    main()