From 05c21eeb2ff4b70069799ab68ccdda31065bfb9e Mon Sep 17 00:00:00 2001 From: Alex Kulikov Date: Thu, 16 Jul 2026 22:40:05 +0100 Subject: [PATCH 1/2] fix: don't shadow exception variable in sender error-handling path The inner "except ... as e" for the error-log redirect send shadowed the outer send failure's "e", and Python deletes that binding when its except block exits. Once the redirect send also failed, reading e.message afterward raised UnboundLocalError, silently swallowing the original error and skipping the plain-text fallback send. Co-Authored-By: Claude Sonnet 5 --- src/tg/sender.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/tg/sender.py b/src/tg/sender.py index 0f3a6ac..77a1e40 100644 --- a/src/tg/sender.py +++ b/src/tg/sender.py @@ -177,6 +177,11 @@ async def _send_to_chat_id_async( return True except telegram.error.TelegramError as e: logger.error(f"Could not send a message to {chat_id}", exc_info=e) + # Captured now: the "except ... as e" binding is cleared by Python + # when its except block exits, and the inner except below rebinds + # its own "e" -- reading e.message after the loop would otherwise + # raise UnboundLocalError once the inner except has fired. + original_error_message = e.message chat_name = AppContext().db_client.get_chat_name(chat_id) for error_logs_recipient in self.error_logs_recipients: try: @@ -194,16 +199,16 @@ async def _send_to_chat_id_async( connect_timeout=SEND_CONNECT_TIMEOUT_SEC, **kwargs, ) - except telegram.error.TelegramError as e: + except telegram.error.TelegramError as redirect_error: logger.error( "Could not redirect unsended message " f"to error_logs_recipients {error_logs_recipient}", - exc_info=e, + exc_info=redirect_error, ) # HTML parse error isn't a separate class in Telegram # So we need to dig into the exception message - if "Can't parse entities" in e.message: + if "Can't parse entities" in original_error_message: try: # Try sending the plain-text version await self.bot.send_message( From f81bd21640d5af3e2588da47cb6713ae553f098d Mon Sep 17 00:00:00 2001 From: Alex Kulikov Date: Fri, 17 Jul 2026 13:37:59 +0100 Subject: [PATCH 2/2] fix: dispatch dev/master deploys to split sysblokbot-testing/prod services sysblok-infra now treats sysblokbot-prod and sysblokbot-testing as independent deploy targets (separate Compose projects) instead of one shared project that got force-recreated on every deploy, restarting prod on dev-only pushes. Point each workflow's repository_dispatch at its own service name to match. Do not merge until the sysblok-infra side (branch fix/split-sysblokbot-deploy-services there) is deployed and the one-time data migration to the new /srv/sysblokbot-prod and /srv/sysblokbot-testing paths is done -- merging first would dispatch deploys to service directories that don't exist yet on the host. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/publish_dev.yml | 2 +- .github/workflows/publish_master.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish_dev.yml b/.github/workflows/publish_dev.yml index e778b99..2df81dd 100644 --- a/.github/workflows/publish_dev.yml +++ b/.github/workflows/publish_dev.yml @@ -83,4 +83,4 @@ jobs: token: ${{ secrets.INFRA_DISPATCH_TOKEN }} repository: sysblok/sysblok-infra event-type: deploy - client-payload: '{"service": "sysblokbot"}' + client-payload: '{"service": "sysblokbot-testing"}' diff --git a/.github/workflows/publish_master.yml b/.github/workflows/publish_master.yml index fdc876a..9b8e876 100644 --- a/.github/workflows/publish_master.yml +++ b/.github/workflows/publish_master.yml @@ -88,4 +88,4 @@ jobs: token: ${{ secrets.INFRA_DISPATCH_TOKEN }} repository: sysblok/sysblok-infra event-type: deploy - client-payload: '{"service": "sysblokbot"}' + client-payload: '{"service": "sysblokbot-prod"}'