From e98eb92b5f09097584b7828e0b0250d7cbd029cf Mon Sep 17 00:00:00 2001 From: Yufeng He <40085740+he-yufeng@users.noreply.github.com> Date: Sat, 18 Apr 2026 20:31:33 +0800 Subject: [PATCH] fix: prevent Telegram media group exceptions from being silently swallowed (#7537) * fix: prevent Telegram media group exceptions from being silently swallowed process_media_group() is invoked by APScheduler via add_job(). If convert_message() or handle_msg() raises (e.g. get_file() network timeout, file download failure), APScheduler catches the exception internally and only logs it through its own logger, which is often not configured in AstrBot. The result is that the media group silently disappears with no trace in the application logs. Two changes: - Wrap the body of process_media_group() in try/except so failures are logged through AstrBot's own logger with full traceback. - Register an EVENT_JOB_ERROR listener on the scheduler as a safety net, so any future scheduled job that throws will also surface in the logs. Fixes #7512 * ruff format --------- Co-authored-by: Soulter <905617992@qq.com> --- .../platform/sources/telegram/tg_adapter.py | 61 ++++++++++++------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/astrbot/core/platform/sources/telegram/tg_adapter.py b/astrbot/core/platform/sources/telegram/tg_adapter.py index a37e5cfd4..76863a194 100644 --- a/astrbot/core/platform/sources/telegram/tg_adapter.py +++ b/astrbot/core/platform/sources/telegram/tg_adapter.py @@ -6,6 +6,7 @@ import uuid from contextlib import suppress from typing import cast +from apscheduler.events import EVENT_JOB_ERROR from apscheduler.schedulers.asyncio import AsyncIOScheduler from telegram import BotCommand, Update from telegram.constants import ChatType @@ -80,6 +81,15 @@ class TelegramPlatformAdapter(Platform): self.last_command_hash = None self.scheduler = AsyncIOScheduler() + self.scheduler.add_listener( + lambda ev: logger.error( + "Scheduled job %s raised: %s", + ev.job_id, + ev.exception, + exc_info=ev.exception, + ), + EVENT_JOB_ERROR, + ) self._terminating = False self._loop: asyncio.AbstractEventLoop | None = None self._polling_recovery_requested = asyncio.Event() @@ -695,31 +705,36 @@ class TelegramPlatformAdapter(Platform): f"Processing media group {media_group_id}, total {len(updates_and_contexts)} items" ) - # Use the first update to create the base message (with reply, caption, etc.) - first_update, first_context = updates_and_contexts[0] - abm = await self.convert_message(first_update, first_context) + try: + # Use the first update to create the base message (with reply, caption, etc.) + first_update, first_context = updates_and_contexts[0] + abm = await self.convert_message(first_update, first_context) - if not abm: - logger.warning( - f"Failed to convert the first message of media group {media_group_id}" + if not abm: + logger.warning( + f"Failed to convert the first message of media group {media_group_id}" + ) + return + + # Add additional media from remaining updates by reusing convert_message + for update, context in updates_and_contexts[1:]: + # Convert the message but skip reply chains (get_reply=False) + extra = await self.convert_message(update, context, get_reply=False) + if not extra: + continue + + # Merge only the message components (keep base session/meta from first) + abm.message.extend(extra.message) + logger.debug( + f"Added {len(extra.message)} components to media group {media_group_id}" + ) + + # Process the merged message + await self.handle_msg(abm) + except Exception: + logger.error( + f"Failed to process media group {media_group_id}", exc_info=True ) - return - - # Add additional media from remaining updates by reusing convert_message - for update, context in updates_and_contexts[1:]: - # Convert the message but skip reply chains (get_reply=False) - extra = await self.convert_message(update, context, get_reply=False) - if not extra: - continue - - # Merge only the message components (keep base session/meta from first) - abm.message.extend(extra.message) - logger.debug( - f"Added {len(extra.message)} components to media group {media_group_id}" - ) - - # Process the merged message - await self.handle_msg(abm) async def handle_msg(self, message: AstrBotMessage) -> None: message_event = TelegramPlatformEvent(