From 60f8e832e0d17825dc3bc6710a12bc88046bc2f1 Mon Sep 17 00:00:00 2001 From: SidQin-cyber Date: Mon, 2 Mar 2026 09:19:52 +0800 Subject: [PATCH] fix(telegram): handle sendVoice caption-too-long by resending without caption When TTS text exceeds Telegram's 1024-char caption limit, sendVoice throws "message caption is too long" and the entire reply (voice + text) is lost. Now catch this specific error, resend the voice note without caption, then deliver the full text as a separate message. Closes #30980 Made-with: Cursor --- src/telegram/bot/delivery.ts | 43 +++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/src/telegram/bot/delivery.ts b/src/telegram/bot/delivery.ts index 748fca00a..abf79c2cc 100644 --- a/src/telegram/bot/delivery.ts +++ b/src/telegram/bot/delivery.ts @@ -35,6 +35,7 @@ import type { StickerMetadata, TelegramContext } from "./types.js"; const PARSE_ERR_RE = /can't parse entities|parse entities|find end of the entity/i; const EMPTY_TEXT_ERR_RE = /message text is empty/i; const VOICE_FORBIDDEN_RE = /VOICE_MESSAGES_FORBIDDEN/; +const CAPTION_TOO_LONG_RE = /caption is too long/i; const FILE_TOO_BIG_RE = /file is too big/i; const TELEGRAM_MEDIA_SSRF_POLICY = { // Telegram file downloads should trust api.telegram.org even when DNS/proxy @@ -230,8 +231,6 @@ export async function deliverReplies(params: { markDelivered(); } catch (voiceErr) { // Fall back to text if voice messages are forbidden in this chat. - // This happens when the recipient has Telegram Premium privacy settings - // that block voice messages (Settings > Privacy > Voice Messages). if (isVoiceMessagesForbidden(voiceErr)) { const fallbackText = reply.text; if (!fallbackText || !fallbackText.trim()) { @@ -256,7 +255,38 @@ export async function deliverReplies(params: { hasReplied = true; } markDelivered(); - // Skip this media item; continue with next. + continue; + } + if (isCaptionTooLong(voiceErr)) { + logVerbose( + "telegram sendVoice caption too long; resending voice without caption + text separately", + ); + const noCaptionParams = { ...mediaParams }; + delete noCaptionParams.caption; + delete noCaptionParams.parse_mode; + await withTelegramApiErrorLogging({ + operation: "sendVoice", + runtime, + fn: () => bot.api.sendVoice(chatId, file, { ...noCaptionParams }), + }); + markDelivered(); + const fallbackText = reply.text; + if (fallbackText?.trim()) { + await sendTelegramVoiceFallbackText({ + bot, + chatId, + runtime, + text: fallbackText, + chunkText, + replyToId: undefined, + thread, + linkPreview, + replyMarkup, + }); + } + if (replyToMessageIdForPayload && !hasReplied) { + hasReplied = true; + } continue; } throw voiceErr; @@ -463,6 +493,13 @@ function isVoiceMessagesForbidden(err: unknown): boolean { return VOICE_FORBIDDEN_RE.test(formatErrorMessage(err)); } +function isCaptionTooLong(err: unknown): boolean { + if (err instanceof GrammyError) { + return CAPTION_TOO_LONG_RE.test(err.description); + } + return CAPTION_TOO_LONG_RE.test(formatErrorMessage(err)); +} + /** * Returns true if the error is Telegram's "file is too big" error. * This happens when trying to download files >20MB via the Bot API.