← Back to PRs

#17769: fix(telegram): preserve reply text in threaded mode dispatch

by Glucksberg open 2026-02-16 05:18 View on GitHub →
channel: telegram size: S experienced-contributor
Fixes #7186 ## Problem In Telegram threaded mode, certain markdown-only inputs (e.g. `>`) render to empty HTML via `markdownToTelegramHtml()`. The empty string is then passed to `bot.api.sendMessage()`, which rejects it with a 400 error: *"message text is empty"*. The reply is silently lost. ## Fix Instead of silently dropping messages when HTML is empty, this fix **falls back to sending the original plain text**: - Extracts the fallback send logic into a reusable `sendPlainFallback()` helper (DRYs up the duplicated `sendMessage` call) - When `markdownToTelegramHtml()` produces empty output, calls `sendPlainFallback()` instead of skipping - Adds `EMPTY_TEXT_ERR_RE` to also catch edge cases where empty text slips past the static check at runtime - If even the fallback text is empty, returns `undefined` gracefully ## Changes - `src/telegram/bot/delivery.ts` — Refactored `sendTelegramText()` with early empty-HTML fallback, shared `sendPlainFallback()` helper, and `EMPTY_TEXT_ERR_RE` error catch - `src/telegram/bot/delivery.test.ts` — Added test: "falls back to plain text when markdown renders to empty HTML in threaded mode" ## Tests ``` ✓ falls back to plain text when markdown renders to empty HTML in threaded mode ``` All existing delivery tests pass. <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR fixes a bug where Telegram threaded mode silently drops replies when markdown-only inputs (e.g., `>`) render to empty HTML via `markdownToTelegramHtml()`. The empty string caused Telegram's `sendMessage` API to reject with a 400 "message text is empty" error. - **Early empty-HTML detection**: Adds a `!htmlText.trim()` check in `sendTelegramText()` to fall back to plain text before attempting the HTML send, avoiding the 400 error entirely. - **DRY refactor**: Extracts the plain-text fallback logic into a shared `sendPlainFallback()` helper, eliminating the duplicated `sendMessage` call that existed in the parse-error catch block. - **Runtime safety net**: Adds `EMPTY_TEXT_ERR_RE` to catch "message text is empty" errors at runtime in case the static check is bypassed. - **Graceful empty handling**: When even the fallback text is empty, `sendPlainFallback()` returns `undefined` instead of throwing. - Test added covering the specific scenario of `>` input in threaded (forum) mode. <h3>Confidence Score: 5/5</h3> - This PR is safe to merge — it adds a defensive fallback path for an edge case without changing normal behavior. - The changes are minimal and focused: an early guard for empty HTML output, a DRY refactor of existing fallback logic, and a runtime safety net regex. The normal (non-empty HTML) code path is unchanged. The added test covers the specific bug scenario. I traced through the full execution path for both the early-return and catch-block fallback and found no issues. - No files require special attention. <sub>Last reviewed commit: 34548ee</sub> <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs