From 43edbae638b5068e428ca82b7f9d6c1266050e25 Mon Sep 17 00:00:00 2001 From: teknium1 <127238744+teknium1@users.noreply.github.com> Date: Wed, 1 Jul 2026 01:45:34 -0700 Subject: [PATCH] fix(telegram): widen NoneType reconnect guard to the conflict-retry path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The network-error reconnect ladder (#55992) captured a stable self._app local across its awaits and failed fast when the adapter was torn down mid-sleep. The 409-conflict retry path had the identical unguarded self._app.updater.start_polling() deref — a concurrent disconnect() during its RETRY_DELAY sleep would raise the same 'NoneType' object has no attribute 'updater' and, on a non-final retry, land in limbo. Apply the same stable-local + fail-fast pattern so the existing except block reschedules or escalates to fatal. --- plugins/platforms/telegram/adapter.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/plugins/platforms/telegram/adapter.py b/plugins/platforms/telegram/adapter.py index 4a8f1c679ca..75d8c42cc70 100644 --- a/plugins/platforms/telegram/adapter.py +++ b/plugins/platforms/telegram/adapter.py @@ -2165,8 +2165,17 @@ class TelegramAdapter(BasePlatformAdapter): await asyncio.sleep(RETRY_DELAY) await self._drain_polling_connections() + # Capture a stable local reference: self._app can be reassigned to + # None by a concurrent disconnect() while we're suspended across + # the awaits above (same race #55992 fixed on the network path). + # Re-reading self._app after that point would raise + # AttributeError deep inside start_polling instead of failing fast + # here, where the except below reschedules or escalates to fatal. + app = self._app try: - await self._app.updater.start_polling( + if not app: + raise RuntimeError("Telegram application was torn down during conflict reconnect") + await app.updater.start_polling( allowed_updates=Update.ALL_TYPES, drop_pending_updates=False, error_callback=self._polling_error_callback_ref,