-
-
Notifications
You must be signed in to change notification settings - Fork 54.2k
Description
Bug Description
When OpenClaw sends proactive messages (via cron job delivery or the message tool with action=send) to a private DM chat on Telegram, it fails with:
GrammyError: Call to 'sendMessage' failed! (400: Bad Request: message thread not found)
This also affects sendDocument.
Root Cause
OpenClaw stores the message_id from the last inbound Telegram message as lastThreadId in the session entry. When a proactive send (cron delivery or message tool) resolves its delivery target, it picks up this lastThreadId and passes it as message_thread_id to the Telegram API.
In group chats with topics, message_thread_id is valid and identifies a forum topic. But in private DM chats, Telegram does not support message_thread_id, so the API rejects it with error 400.
Regular replies work fine because they use reply_to_message_id (different parameter), not message_thread_id.
Code Path
deliveryContextFromSession()readslastThreadIdfrom session entryresolveSessionDeliveryTarget()propagates it asthreadIdresolveAgentDeliveryPlan()setsresolvedThreadId- Final send includes
threadIdasmessage_thread_idin the Telegram API call
The lastThreadId is repopulated on every inbound message, so clearing it from sessions.json does not persist.
Expected Behavior
OpenClaw should NOT pass message_thread_id to the Telegram API when the target chat is a private DM (not a group with topics/forum enabled).
Reproduction
- Configure OpenClaw with a Telegram channel targeting a private DM chat
- Create a cron job with
delivery.mode: "announce"targeting that chat - The cron delivery will fail with the thread error
- Using the message tool with
action=sendand afilePathalso fails
Environment
- OpenClaw version:
2026.2.6-3 - Telegram Bot API via Grammy
- Private DM chat (not a group/supergroup with topics)
Suggested Fix
When resolving the delivery target for Telegram, check the chat type. If it is a private chat, do not include message_thread_id in the API call. Alternatively, provide a config option to disable thread tracking per channel.