-
-
Notifications
You must be signed in to change notification settings - Fork 54.7k
Description
Bug Report
Summary
The Telegram reply dispatcher (dispatchReplyWithBufferedBlockDispatcher) silently catches delivery errors via its onError callback, which logs to runtime.error() but does not re-throw or propagate the failure. This means messages can fail to deliver to Telegram without any indication to the user — the message appears on the dashboard/webchat but never reaches Telegram.
Observed Behavior
- Assistant generates a response (visible in session transcript with
stopReason: "stop") - The response appears on the OpenClaw dashboard
- The response never arrives on Telegram
- No error is surfaced to the user or the agent
- The session transcript contains no delivery error record
Expected Behavior
- Delivery failures should be propagated or at least recorded in the session transcript
- The agent should be notified that delivery failed so it can retry or use the
messagetool as fallback - Ideally, the dispatcher should retry delivery at least once before giving up
Root Cause (from source analysis)
In src/telegram/bot-message-dispatch.ts, the dispatchReplyWithBufferedBlockDispatcher is called with an onError handler that catches exceptions:
onError: (err, info) => {
runtime.error?.(danger(`telegram ${info.kind} reply failed: ${String(err)}`));
},This logs the error but does not re-throw, so the error is silently consumed. The deliveryState.delivered remains false, but the only fallback is sending EMPTY_RESPONSE_FALLBACK — which may also fail via the same silent path.
Likely Trigger
Formatted messages containing markdown (bold, backticks, em dashes, bullet points) that cause Telegram's HTML parser to reject the message. There is a fallback from HTML to plain text, but if both fail, the error is swallowed.
Additional Issue: No Retry on Inbound Media Fetch
fetchRemoteMedia (used for inbound Telegram media downloads from api.telegram.org/file/) also has zero retries. A single transient TCP failure (TypeError: fetch failed) results in permanent media loss for that message. We observed intermittent failures at multiple timestamps that resolved after a gateway restart, suggesting transient network/connection pool issues.
Suggested Fix
- Propagate errors: Record delivery failures in the session transcript so the agent can detect them
- Add retry: Retry delivery at least once (with a short delay) before giving up
- Notify agent: If delivery fails after retries, inject a system message so the agent can attempt redelivery via the
messagetool - Add retry to fetchRemoteMedia: At least one retry with backoff for inbound media downloads
- Log persistently: Consider writing delivery failures to a log file, not just
runtime.error()
Environment
- OpenClaw: 2026.2.12
- Channel: Telegram (polling mode,
streamMode: "partial") - Node.js: v22.22.0
- Grammy: 1.40.0
- Undici: 7.21.0
- OS: Ubuntu Linux x64