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
This commit is contained in:
SidQin-cyber
2026-03-02 09:19:52 +08:00
committed by Peter Steinberger
parent a262a3ea08
commit 60f8e832e0

View File

@@ -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.