Telegram silently truncates long messages instead of splitting them
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 2.4k
- Forks
- 314
- Avg merge
- 1d 18h
- Merged PRs (30d)
- 63
Description
Bug Description
@chat-adapter/telegram silently discards the remainder of long messages. postMessage() renders the postable content, passes the rendered text through truncateForTelegram(..., 4096, ...), and sends only the truncated result.
This is especially surprising for { markdown } messages: MarkdownV2 escaping expands the wire payload, so source text can be cut substantially before its own length reaches the apparent platform boundary. The caller receives a successful SentMessage and has no indication that content was lost.
This is the concrete Telegram symptom of the broader contract problem discussed in #408.
Steps to Reproduce
- Create a Chat SDK bot using
@chat-adapter/telegram. - In a Telegram handler, post a Markdown response whose rendered MarkdownV2 output exceeds 4,096 characters.
- Trigger the handler from Telegram.
- Observe that Telegram receives one message ending in an ellipsis and never receives the remainder.
Expected Behavior
Long Telegram posts should not silently lose content. When configured to split long messages, the adapter should send the complete response as ordered consecutive messages, with each payload inside Telegram's limit and with valid formatting.
Short messages should continue to produce one Telegram message.
Actual Behavior
Only one Telegram message is sent. It is truncated to 4,096 characters after rendering, with an ellipsis appended. Everything after the cutoff is discarded.
Code Sample
import { createTelegramAdapter } from '@chat-adapter/telegram';
import { Chat } from 'chat';
const bot = new Chat({
userName: 'mybot',
adapters: {
telegram: createTelegramAdapter({ mode: 'polling' }),
},
});
bot.onNewMention(async (thread) => {
const longMarkdown = Array.from(
{ length: 200 },
(_, index) => `## Section ${index + 1}\n\n- Result with punctuation: value_${index}.`,
).join('\n\n');
await thread.post({ markdown: longMarkdown });
});
Chat SDK Version
chat@4.28.1, @chat-adapter/telegram@4.28.1
Node.js Version
24.14.0
Platform Adapter
Telegram
Operating System
macOS
Additional Context
In a real n8n Agent reproduction, the stored assistant response contained 6,291 source characters. Telegram cut the visible response around source character 3,932 because MarkdownV2 escaping expanded the rendered payload to the adapter's 4,096-character truncation boundary.
Current main still retains truncateForTelegram() for classic/fallback Telegram message paths. Newer rich-message support raises the ceiling for supported Bot API versions, but it does not eliminate silent data loss in fallback paths or above the rich-message limit.
A useful adapter-level resolution would be an explicit long-message strategy such as the "split" option proposed in #408. Splitting belongs in the adapter because it owns final rendering, Telegram-specific limits, formatting validity, and the semantics of returning one SentMessage for multiple API posts.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the Telegram adapter's postMessage() path and truncateForTelegram(), then read the broader long-message contract discussed in #408. Verify rendered MarkdownV2 and fallback paths; done means a configured split strategy sends complete, ordered, validly formatted chunks within Telegram's limit, while short messages remain single sends and no content is silently discarded.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100