Skip to content

fix(telegram): skip message_thread_id for private chats to prevent silent message drops (v2)#19050

Open
Limitless2023 wants to merge 1 commit intoopenclaw:mainfrom
Limitless2023:fix/telegram-private-chat-thread-id-v2
Open

fix(telegram): skip message_thread_id for private chats to prevent silent message drops (v2)#19050
Limitless2023 wants to merge 1 commit intoopenclaw:mainfrom
Limitless2023:fix/telegram-private-chat-thread-id-v2

Conversation

@Limitless2023
Copy link
Contributor

@Limitless2023 Limitless2023 commented Feb 17, 2026

Improved v2 of #17252Fixes #17242

Closes #17242

Problem

When sending messages to Telegram private chats (positive chatId), the opts-level messageThreadId — typically derived from reply-context — is passed as message_thread_id to the Telegram API. Private chats don't support forum topics, so the API rejects with:

400: Bad Request: message thread not found

Messages are silently dropped, affecting:

  • Sub-agent announce notifications (sessions_spawn)
  • Cron job deliveries to private chats
  • Proactive message tool sends

Root cause

buildTelegramThreadReplyParams unconditionally merges opts.messageThreadId into the thread spec for all chat types, including private chats where message_thread_id is invalid.

Fix

In buildTelegramThreadReplyParams, private chats (chatType === "direct") now only honour the thread ID embedded in the target address (e.g., 123456789:topic:42) and ignore the opts-level messageThreadId.

This is a single-point fix that covers all send paths: text messages, media, stickers, and polls — addressing the reviewer feedback on #17252 about missing sticker/poll checks.

Why not blanket-strip?

Previous #17252 was rejected because blanket-suppressing message_thread_id for all private chats would break DM topic routing (Bot API 9.3, #18974). This v2 distinguishes between:

Source Private chat behaviour Rationale
Target address (123456789:topic:42) Kept Intentional DM topic routing
opts.messageThreadId (reply context) Skipped Reply-context thread IDs don't apply to plain DMs

Changes

  • src/telegram/send.tsbuildTelegramThreadReplyParams: for private chats, use only targetMessageThreadId (from target string), ignore opts.messageThreadId
  • src/telegram/send.test.ts — Updated/added tests:
    • Verifies opts-level messageThreadId is skipped for private chat text sends
    • Verifies target-embedded thread IDs are preserved for DM topics
    • Verifies opts-level messageThreadId is skipped for private chat sticker sends
    • Updated chat-not-found test to use group chatId (was using private chatId with now-skipped thread param)

Test results

All 38 telegram test files pass (469 tests).

Greptile Summary

This PR fixes silent message drops when sending to Telegram private chats with a reply-context messageThreadId (#17242). The root cause was buildTelegramThreadReplyParams unconditionally forwarding opts.messageThreadId (from reply context) to the API as message_thread_id, which private chats reject with 400: Bad Request: message thread not found.

The fix is a single-point change in buildTelegramThreadReplyParams:

  • Private chats (chatType === "direct"): only use the thread ID embedded in the target address (e.g., 123456789:topic:42), ignoring the opts-level messageThreadId
  • Group/unknown chats: preserve the existing precedence (opts.messageThreadId takes priority, falls back to targetMessageThreadId)

This covers all send paths (text, media, stickers, polls) since they all flow through buildTelegramThreadReplyParams.

  • Tests updated to verify opts-level thread ID is skipped for private text and sticker sends
  • New test verifies target-embedded thread IDs are preserved for DM topic routing (Bot API 9.3)
  • Existing chat-not-found test updated to use group chat ID (since private chats now skip opts thread ID, the old assertion was invalid)

Confidence Score: 5/5

  • This PR is safe to merge — it's a well-scoped fix with correct logic and thorough test coverage.
  • The change is minimal (6 lines of logic in one function), the fix is correct based on Telegram API semantics, it preserves existing behavior for non-private chats, and the tests comprehensively cover the key scenarios: opts-level thread ID skipped for private chats, target-embedded thread ID preserved for DM topics, and group chat behavior unchanged. The ?? operator is semantically equivalent to the previous != null ternary for the non-private path.
  • No files require special attention.

Last reviewed commit: 3cd7e0d

… prevent silent message drops

For private chats (chatId > 0), the opts-level messageThreadId — which
typically comes from reply-context — caused Telegram to reject sends
with '400: Bad Request: message thread not found'.  Messages were
silently dropped, affecting sub-agent notifications, cron deliveries,
and proactive messages.

The fix: in buildTelegramThreadReplyParams, private chats now only use
the thread ID embedded in the target address (e.g. '123456789:topic:42')
and ignore the opts-level messageThreadId.  This preserves DM topic
routing (Bot API 9.3, openclaw#18974) while fixing the silent drop for plain
private chats.

Applies to all send paths: text, media, stickers, and polls.

Closes openclaw#17242
@openclaw-barnacle openclaw-barnacle bot added channel: telegram Channel integration: telegram size: S labels Feb 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: telegram Channel integration: telegram size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Telegram: message_thread_id sent in private chats causes 400 "message thread not found", silently drops messages

2 participants

Comments