[Python] Pyrofork Handler Silent Failure #Critical Issue

Discussão em 'Python' iniciado por Stack, Agosto 30, 2025.

  1. Stack

    Stack Membro Participativo

    Pyrogram Bot Not Responding to /start Command - No Errors Logged


    I'm developing a Telegram bot using Pyrogram, but the /start command doesn't trigger any response, and no errors are logged. The bot starts successfully, and the logs indicate that the bot and user clients are initialized, but the command handler in start.py seems to be ignored. I've tried registering the handler in different ways, but nothing works. Below are the relevant files from my project. Can someone help identify why the /start command isn't registering or responding?

    Project Structure

    • SmartBot/bot/__main__.py: Main entry point for the bot.
    • SmartBot/bot/__init__.py: Exports client instances.
    • SmartBot/bot/clients.py: Defines bot and user clients.
    • SmartBot/bot/modules/start.py: Handles the /start command.
    • SmartBot/bot/helpers/botutils.py: Utility functions for sending/deleting messages.
    • SmartBot/bot/buttons.py: Custom button builder for inline keyboards.
    • SmartBot/bot/helpers/commands.py: Defines command prefixes.
    • SmartBot/config.py: Configuration and environment variable handling.
    Code Details

    SmartBot/bot/__main__.py


    import asyncio
    import os
    import importlib
    from pyrogram import idle, handlers
    from bot.helpers.logger import LOGGER
    from bot.miscs import SmartCallback
    from bot.clients import SmartGram, SmartUser
    from bot.core.database import check_restart

    def import_all_modules_from_dir(package):
    base_path = os.path.join(os.path.dirname(__file__), "modules")
    for root, dirs, files in os.walk(base_path):
    rel_path = os.path.relpath(root, base_path)
    if rel_path == ".":
    rel_path = ""
    for file in files:
    if file.endswith(".py") and not file.startswith("__"):
    mod_name = file[:-3]
    if rel_path:
    import_name = f"{package}.{rel_path.replace(os.sep, '.')}.{mod_name}"
    else:
    import_name = f"{package}.{mod_name}"
    importlib.import_module(import_name)
    LOGGER.info(f"Imported module: {import_name}")

    def register_bot_handlers():
    SmartGram.add_handler(handlers.CallbackQueryHandler(SmartCallback))

    async def main():
    await SmartGram.start()
    await SmartUser.start()
    import_all_modules_from_dir("bot.modules")
    register_bot_handlers()
    LOGGER.info("Bot Successfully Started!")

    restart_data = await check_restart.find_one()
    if restart_data:
    try:
    await SmartGram.edit_message_text(
    chat_id=restart_data["chat_id"],
    message_id=restart_data["msg_id"],
    text="**Restarted Successfully **",
    parse_mode="markdown"
    )
    await check_restart.delete_one({"_id": restart_data["_id"]})
    LOGGER.info(f"Restart message updated and cleared from database for chat {restart_data['chat_id']}")
    except Exception as e:
    LOGGER.error(f"Failed to update restart message: {e}")

    await idle()

    if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    try:
    loop.run_until_complete(main())
    except KeyboardInterrupt:
    LOGGER.info("Stop signal received. Shutting down...")
    try:
    stop_tasks = []
    if SmartGram.is_connected:
    stop_tasks.append(SmartGram.stop())
    if SmartUser.is_connected:
    stop_tasks.append(SmartUser.stop())
    if stop_tasks:
    loop.run_until_complete(asyncio.gather(*stop_tasks))
    except Exception as e:
    LOGGER.error(f"Failed to stop clients: {e}")
    finally:
    if not loop.is_closed():
    loop.close()

    SmartBot/bot/__init__.py


    from .clients import SmartGram, SmartUser

    SmartBot/bot/clients.py


    from pyrogram import Client
    from config import API_ID, API_HASH, BOT_TOKEN, SESSION_STRING
    from bot.helpers.logger import LOGGER

    LOGGER.info("Creating Bot Client From BOT_TOKEN")
    SmartGram = Client(
    "QuickUtilBot",
    api_id=API_ID,
    api_hash=API_HASH,
    bot_token=BOT_TOKEN,
    workers=1000
    )
    LOGGER.info("Bot Client Created Successfully!")

    LOGGER.info("Creating User Client From SESSION_STRING")
    SmartUserBot = Client(
    "QuickUserBot",
    session_string=SESSION_STRING,
    workers=1000
    )
    LOGGER.info("User Client Successfully Created!")

    SmartBot/bot/modules/start.py


    from bot.clients import SmartGram
    from bot.helpers.logger import LOGGER
    from bot.helpers.botutils import send_message, delete_messages
    from bot.helpers.buttons import SmartButtons
    from bot.helpers.commands import BotCommand
    from pyrogram import filters
    from pyrogram.enums import ParseMode, ChatType
    import asyncio
    from config import UPDATE_CHANNEL_URL, BAN_REPLY

    @SmartGram.on_message(filters.command(["start"], prefixes=BotCommand) & (filters.private | filters.group))
    async def start_message(client, message):
    chat_id = message.chat.id
    animation_message = await send_message(chat_id, "<b>Starting Smart Tool ⚙️...</b>", parse_mode=ParseMode.HTML)
    await asyncio.sleep(0.4)

    loading_message = await send_message(
    chat_id,
    "<b>Generating Session Keys Please Wait...</b>",
    parse_mode=ParseMode.HTML,
    reply_to_message_id=animation_message.id if animation_message else None
    )
    await asyncio.sleep(0.4)

    if animation_message:
    await delete_messages(chat_id, animation_message.id)

    if message.chat.type == ChatType.PRIVATE:
    full_name = "User"
    if message.from_user:
    first_name = message.from_user.first_name or ""
    last_name = message.from_user.last_name or ""
    full_name = f"{first_name} {last_name}".strip()
    response_text = (
    f"<b>Hi {full_name}! Welcome To This Bot</b>\n"
    "<b>━━━━━━━━━━━━━━━━━━━━━━</b>\n"
    f"<b>Smart Tool</b> The ultimate toolkit on Telegram, offering education, AI, downloaders, temp mail, credit cards, and more. Simplify your tasks with ease!\n"
    "<b>━━━━━━━━━━━━━━━━━━━━━━</b>\n"
    f"<b>Don't forget to <a href='{UPDATE_CHANNEL_URL}'>Join Here</a> for updates!</b>"
    )
    else:
    group_name = message.chat.title if message.chat.title else "this group"
    if message.from_user:
    first_name = message.from_user.first_name or ""
    last_name = message.from_user.last_name or ""
    full_name = f"{first_name} {last_name}".strip()
    response_text = (
    f"<b>Hi {full_name}! Welcome To This Bot</b>\n"
    "<b>━━━━━━━━━━━━━━━━━━━━━━</b>\n"
    f"<b>Smart Tool</b> The ultimate toolkit on Telegram, offering education, AI, downloaders, temp mail, credit cards, and more. Simplify your tasks with ease!\n"
    "<b>━━━━━━━━━━━━━━━━━━━━━━</b>\n"
    f"<b>Don't forget to <a href='{UPDATE_CHANNEL_URL}'>Join Here</a> for updates!</b>"
    )
    else:
    response_text = (
    f"<b>Hi! Welcome {group_name} To This Bot</b>\n"
    "<b>━━━━━━━━━━━━━━━━━━━━━━</b>\n"
    f"<b>Smart Tool</b> The ultimate toolkit on Telegram, offering education, AI, downloaders, temp mail, credit cards, and more. Simplify your tasks with ease!\n"
    "<b>━━━━━━━━━━━━━━━━━━━━━━</b>\n"
    f"<b>Don't forget to <a href='{UPDATE_CHANNEL_URL}'>Join Here</a> for updates!</b>"
    )

    buttons = SmartButtons()
    buttons.button("⚙️ Main Menu", callback_data="main_menu")
    buttons.button("ℹ️ About Me", callback_data="about_me")
    buttons.button(" Policy & Terms", callback_data="policy_terms")

    await send_message(
    chat_id=chat_id,
    text=response_text,
    parse_mode=ParseMode.HTML,
    reply_markup=buttons.build_menu(b_cols=2),
    disable_web_page_preview=True
    )

    SmartBot/bot/helpers/botutils.py


    from bot import SmartGram
    from bot.helpers import LOGGER
    from pyrogram.types import Message
    from pyrogram.enums import ParseMode

    async def send_message(chat_id, text, parse_mode=ParseMode.HTML, reply_markup=None, reply_to_message_id=None, disable_web_page_preview=False):
    try:
    return await SmartGram.send_message(
    chat_id=chat_id,
    text=text,
    parse_mode=parse_mode,
    reply_markup=reply_markup,
    reply_to_message_id=reply_to_message_id,
    disable_web_page_preview=disable_web_page_preview
    )
    except Exception as e:
    LOGGER.error(f"Failed to send message to {chat_id}: {e}")
    return None

    def get_args(message: Message):
    if not message.text:
    return []
    text = message.text.split(None, 1)
    if len(text) < 2:
    return []
    args = text[1].strip()
    if not args:
    return []
    result = []
    current = ""
    in_quotes = False
    quote_char = None
    i = 0
    while i < len(args):
    char = args
    if char in ('"', "'") and (i == 0 or args[i-1] != '\\'):
    if in_quotes and char == quote_char:
    in_quotes = False
    quote_char = None
    if current:
    result.append(current)
    current = ""
    else:
    in_quotes = True
    quote_char = char
    elif char == ' ' and not in_quotes:
    if current:
    result.append(current)
    current = ""
    else:
    current += char
    i += 1
    if current:
    result.append(current)
    return result

    async def delete_messages(chat_id, message_ids):
    try:
    if isinstance(message_ids, int):
    message_ids = [message_ids]
    await SmartGram.delete_messages(chat_id=chat_id, message_ids=message_ids)
    LOGGER.info(f"Deleted messages {message_ids} in chat {chat_id}")
    return True
    except Exception as e:
    LOGGER.error(f"Failed to delete messages {message_ids} in chat {chat_id}: {e}")
    return False

    SmartBot/bot/buttons.py


    from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, WebAppInfo, LoginUrl, CallbackGame
    from ..helpers import LOGGER

    class SmartButtons:
    def __init__(self):
    self._button = []
    self._header_button = []
    self._footer_button = []

    def button(self, text, callback_data=None, url=None, web_app=None, login_url=None, user_id=None, switch_inline_query=None, switch_inline_query_current_chat=None, callback_game=None, copy_text=None, position=None):
    kwargs = {}
    if callback_data is not None:
    kwargs["callback_data"] = callback_data
    elif url is not None:
    kwargs["url"] = url
    elif web_app is not None:
    kwargs["web_app"] = web_app
    elif login_url is not None:
    kwargs["login_url"] = login_url
    elif user_id is not None:
    kwargs["user_id"] = user_id
    elif switch_inline_query is not None:
    kwargs["switch_inline_query"] = switch_inline_query
    elif switch_inline_query_current_chat is not None:
    kwargs["switch_inline_query_current_chat"] = switch_inline_query_current_chat
    elif callback_game is not None:
    kwargs["callback_game"] = callback_game
    elif copy_text is not None:
    kwargs["copy_text"] = copy_text
    else:
    LOGGER.error("At least one optional parameter must be provided for InlineKeyboardButton")
    return
    button = InlineKeyboardButton(text=text, **kwargs)
    if not position:
    self._button.append(button)
    elif position == "header":
    self._header_button.append(button)
    elif position == "footer":
    self._footer_button.append(button)

    def build_menu(self, b_cols=1, h_cols=8, f_cols=8):
    menu = [self._button[i:i + b_cols] for i in range(0, len(self._button), b_cols)]
    if self._header_button:
    h_cnt = len(self._header_button)
    if h_cnt > h_cols:
    header_buttons = [self._header_button[i:i + h_cols] for i in range(0, len(self._header_button), h_cols)]
    menu = header_buttons + menu
    else:
    menu.insert(0, self._header_button)
    if self._footer_button:
    if len(self._footer_button) > f_cols:
    [menu.append(self._footer_button[i:i + f_cols]) for i in range(0, len(self._footer_button), f_cols)]
    else:
    menu.append(self._footer_button)
    return InlineKeyboardMarkup(menu)

    def reset(self):
    self._button = []
    self._header_button = []
    self._footer_button = []

    SmartBot/bot/helpers/commands.py


    from config import COMMAND_PREFIX

    BotCommand = COMMAND_PREFIX

    SmartBot/config.py


    #Copyright @ISmartCoder
    #Updates Channel: https://t.me/TheSmartDev
    import os
    from dotenv import load_dotenv

    load_dotenv()

    def get_env_or_default(key, default=None, cast_func=str):
    value = os.getenv(key)
    if value is not None and value.strip() != "":
    try:
    return cast_func(value)
    except (ValueError, TypeError) as e:
    print(f"Error casting {key} with value '{value}' to {cast_func.__name__}: {e}")
    return default
    return default

    API_ID = get_env_or_default("API_ID", "Your_API_ID_Here")
    API_HASH = get_env_or_default("API_HASH", "Your_API_HASH_Here")
    BOT_TOKEN = get_env_or_default("BOT_TOKEN", "Your_BOT_TOKEN_Here")
    SESSION_STRING = get_env_or_default("SESSION_STRING", "Your_SESSION_STRING_Here")

    OWNER_ID = get_env_or_default("OWNER_ID", "Your_OWNER_ID_Here", int)
    DEVELOPER_USER_ID = get_env_or_default("DEVELOPER_USER_ID", "Your_DEVELOPER_USER_ID_Here", int)

    MONGO_URL = get_env_or_default("MONGO_URL", "Your_MONGO_URL_Here")
    DATABASE_URL = get_env_or_default("DATABASE_URL", "Your_DATABASE_URL_Here")
    DB_URL = get_env_or_default("DB_URL", "Your_DB_URL_Here")

    OPENAI_API_KEY = get_env_or_default("OPENAI_API_KEY", "Your_OPENAI_API_KEY_Here")
    REPLICATE_API_TOKEN = get_env_or_default("REPLICATE_API_TOKEN", "Your_REPLICATE_API_TOKEN_Here")
    GOOGLE_API_KEY = get_env_or_default("GOOGLE_API_KEY", "Your_GOOGLE_API_KEY_Here")
    OCR_API_KEY = get_env_or_default("OCR_API_KEY", "Your_OCR_API_KEY_Here")
    TRANS_API_KEY = get_env_or_default("TRANS_API_KEY", "Your_TRANS_API_KEY_Here")
    MODEL_NAME = get_env_or_default("MODEL_NAME", "gemini-2.0-flash")

    CC_SCRAPPER_LIMIT = get_env_or_default("CC_SCRAPPER_LIMIT", 5000, int)
    SUDO_CCSCR_LIMIT = get_env_or_default("SUDO_CCSCR_LIMIT", 10000, int)
    MULTI_CCSCR_LIMIT = get_env_or_default("MULTI_CCSCR_LIMIT", 2000, int)
    MAIL_SCR_LIMIT = get_env_or_default("MAIL_SCR_LIMIT", 10000, int)
    SUDO_MAILSCR_LIMIT = get_env_or_default("SUDO_MAILSCR_LIMIT", 15000, int)
    CC_GEN_LIMIT = get_env_or_default("CC_GEN_LIMIT", 2000, int)
    MULTI_CCGEN_LIMIT = get_env_or_default("MULTI_CCGEN_LIMIT", 5000, int)

    GOOGLE_API_KEY = get_env_or_default("GOOGLE_API_KEY", "Your_GOOGLE_API_KEY_Here")
    MODEL_NAME = get_env_or_default("MODEL_NAME", "gemini-1.5 HEM")
    GROQ_API_KEY = get_env_or_default("GROQ_API_KEY", "Your_GROQ_API_KEY_Here")
    GROQ_API_URL = get_env_or_default("GROQ_API_URL", "https://api.groq.com/openai/v1/chat/completions")
    DOMAIN_API_KEY = get_env_or_default("DOMAIN_API_KEY", "Your_DOMAIN_API_KEY_Here")
    DOMAIN_API_URL = get_env_or_default("DOMAIN_API_URL", "https://www.whoisxmlapi.com/whoisserver/WhoisService")
    TEXT_MODEL = get_env_or_default("TEXT_MODEL", "deepseek-r1-distill-llama-70b")
    NEWS_API_KEY = get_env_or_default("NEWS_API_KEY", "Your_NEWS_API_KEY_Here")
    BIN_KEY = get_env_or_default("BIN_KEY", "Your_BIN_KEY_Here")

    raw_prefixes = get_env_or_default("COMMAND_PREFIX", "!|.|#|,|/")
    COMMAND_PREFIX = [prefix.strip() for prefix in raw_prefixes.split("|") if prefix.strip()]

    UPDATE_CHANNEL_URL = get_env_or_default("UPDATE_CHANNEL_URL", "https://t.me/TheSmartDev")
    LOG_CHANNEL_ID = get_env_or_default("LOG_CHANNEL_ID", "-100432424242")

    IMGAI_SIZE_LIMIT = get_env_or_default("IMGAI_SIZE_LIMIT", 5242880, int)
    MAX_TXT_SIZE = get_env_or_default("MAX_TXT_SIZE", 15728640, int)
    MAX_VIDEO_SIZE = get_env_or_default("MAX_VIDEO_SIZE", 2147483648, int)

    YT_COOKIES_PATH = get_env_or_default("YT_COOKIES_PATH", "./cookies/ISmartToolBot.txt")

    VIDEO_RESOLUTION = get_env_or_default("VIDEO_RESOLUTION", "1280x720", lambda x: tuple(map(int, x.split('x'))))

    DOMAIN_CHK_LIMIT = get_env_or_default("DOMAIN_CHK_LIMIT", 20, int)
    PROXY_CHECK_LIMIT = get_env_or_default("PROXY_CHECK_LIMIT", 20, int)

    BAN_REPLY = get_env_or_default("BAN_REPLY", "**Sorry Bro You're Banned From Using Me ❌**")

    required_vars = {
    "API_ID": API_ID,
    "API_HASH": API_HASH,
    "BOT_TOKEN": BOT_TOKEN,
    "SESSION_STRING": SESSION_STRING,
    "OWNER_ID": OWNER_ID,
    "DEVELOPER_USER_ID": DEVELOPER_USER_ID,
    "MONGO_URL": MONGO_URL,
    "DATABASE_URL": DATABASE_URL
    }

    for var_name, var_value in required_vars.items():
    if var_value is None or var_value == f"Your_{var_name}_Here" or (isinstance(var_value, str) and var_value.strip() == ""):
    raise ValueError(f"Required variable {var_name} is missing or invalid. Set it in .env (VPS), config.py (VPS), or Heroku config vars.")

    print("Loaded COMMAND_PREFIX:", COMMAND_PREFIX)
    gpt_api_key_source = "environment variable" if os.getenv("OPENAI_API_KEY") else "config default"
    print(f"OPENAI_API_KEY loaded from {gpt_api_key_source}: {'*' * 10}{OPENAI_API_KEY[-10:]}")

    if not COMMAND_PREFIX:
    raise ValueError("No command prefixes found. Set COMMAND_PREFIX in .env, config.py, or Heroku config vars.")

    Issue Description

    • The bot starts without issues, and logs confirm that SmartGram and SmartUser clients are created and started.
    • The start.py module is imported via import_all_modules_from_dir("bot.modules"), and I see logs confirming the module is loaded.
    • The /start command (with prefixes like !, ., #, ,, /) does not trigger the start_message function in start.py.
    • No errors are logged in the console or the logger when sending the /start command.
    • The SmartCallback handler for callback queries is registered in __main__.py, but I suspect the message handler for /start is not being registered properly.
    • I tried moving the handler registration to the main() function, but it had no effect.
    Environment

    • Python: 3.11
    • Pyrogram: Pyrofork Latest 2.3.68
    • Deployment: Local machine (tested on VPS as well)
    • OS: Ubuntu
    What I've Tried

    1. Verified that BotCommand in commands.py correctly loads the prefixes from config.py.
    2. Ensured SmartGram is the correct client instance used in start.py.
    3. Checked that start.py is imported correctly by the import_all_modules_from_dir function.
    4. Tested with different command prefixes (/start, !start, etc.) in both private and group chats.
    5. Added debug logs in start.py to confirm the handler is reached (none are triggered).
    6. Ensured all required environment variables (API_ID, API_HASH, BOT_TOKEN, etc.) are set correctly in the .env file.
    Questions

    1. Why is the /start command handler not being triggered despite the module being imported?
    2. Is there an issue with how I'm registering handlers or importing modules?
    3. Could there be a problem with the Pyrogram client configuration or the filter setup in start.py?
    4. How can I debug this further to pinpoint why the handler isn't responding?

    Any help from experienced Pyrogram developers would be greatly appreciated! Please let me know if you need more details or additional files (e.g., logger.py or miscs.py).

    Continue reading...

Compartilhe esta Página