Skip to content

fix(telegram): fail DM topic sends without threadless retry#78575

Merged
obviyus merged 1 commit into
openclaw:mainfrom
tmimmanuel:fix/78463-stale-running-tasks
May 9, 2026
Merged

fix(telegram): fail DM topic sends without threadless retry#78575
obviyus merged 1 commit into
openclaw:mainfrom
tmimmanuel:fix/78463-stale-running-tasks

Conversation

@tmimmanuel

@tmimmanuel tmimmanuel commented May 6, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Problem: Telegram DM/private-topic sends can fail with 400: Bad Request: message thread not found, but OpenClaw used to retry without the thread id and report success after sending into the plain DM instead of the intended topic.
  • Why it matters: Users see a successful CLI/API result even though the message was not delivered to the requested Telegram topic, which hides Telegram routing failures and can put responses in the wrong conversation surface.
  • What changed: Telegram DM-topic outbound sends now preserve the requested thread requirement and surface Telegram's message thread not found error instead of silently retrying threadless. Quote/formatting fallback behavior remains separate.
  • What did NOT change (scope boundary): This PR does not claim to make Telegram deliver to the affected DM topic while Telegram rejects the topic id. It prevents false success and wrong-surface delivery. No gateway/task-registry changes and no UI/config behavior changes.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Real behavior proof (required for external PRs)

  • Behavior or issue addressed: Telegram DM-topic sends should not be reported as successful when Telegram rejects the requested topic id. The fix changes the real runtime behavior from “fallback to plain DM and return success” to “surface the Telegram failure.”
  • Real environment tested: Ubuntu workstation, Node 22.22.0 via nvm, pnpm 10.33.2, OpenClaw gateway running from PR head dbec502085 (fix/78463-stale-running-tasks), Telegram bot @tmimmanuel_openclaw_bot, target chat 7116088418, topic id 42159.
  • Exact steps or command run after this patch:
    1. Checked out PR head dbec502085 in /home/ubuntu/codes/tmimmanuel/openclaw-pr-78575.
    2. Ran pnpm install --frozen-lockfile.
    3. Started the gateway from the PR checkout with pnpm start gateway run --verbose.
    4. Sent a live Telegram DM-topic message through the gateway:
pnpm start message send \
  --channel telegram \
  --target 7116088418 \
  --thread-id 42159 \
  --message '[openclaw #79455 PR78575 retest 2026-05-09T03:30Z] no threadless fallback expected' \
  --json --verbose
  • Evidence after fix (copied live terminal output and runtime log):
$ pnpm start message send --channel telegram --target 7116088418 --thread-id 42159 --message '[openclaw #79455 PR78575 retest 2026-05-09T03:30Z] no threadless fallback expected' --json --verbose

GatewayClientRequestError: GrammyError: Call to 'sendMessage' failed! (400: Bad Request: message thread not found)
ELIFECYCLE Command failed with exit code 1.
exit_status=1
2026-05-09T03:30:29.755+00:00 [telegram] message failed: Call to 'sendMessage' failed! (400: Bad Request: message thread not found)
2026-05-09T03:30:29.759+00:00 [ws] ⇄ res ✗ message.action 294ms errorCode=UNAVAILABLE errorMessage=GrammyError: Call to 'sendMessage' failed! (400: Bad Request: message thread not found) channel=telegram
  • Observed result after fix: The gateway no longer returns a successful message.action after dropping the topic id. The CLI exits non-zero and exposes Telegram's message thread not found error, so OpenClaw does not silently send into the plain DM.
  • What was not tested: Successful delivery into the exact Telegram DM topic, because Telegram still rejected message_thread_id for this bot/topic during the live test. A separate Telegram server/API fix or a reliable direct-topic parameter would be needed for successful topic delivery.
  • Before evidence (optional but encouraged): On synced main 50898c4a72, the same target/topic returned success after fallback while logging the same Telegram rejection:
$ pnpm start message send --channel telegram --target 7116088418 --thread-id 42159 --message '[openclaw #79455 main retest 2026-05-09T01:56Z] synced main message_thread_id behavior' --json --verbose
{
  "action": "send",
  "channel": "telegram",
  "dryRun": false,
  "handledBy": "plugin",
  "payload": {
    "ok": true,
    "messageId": "15",
    "chatId": "7116088418"
  }
}

2026-05-09T01:56:14.179+00:00 [telegram] message failed: Call to 'sendMessage' failed! (400: Bad Request: message thread not found)
2026-05-09T01:56:14.389+00:00 [ws] ⇄ res ✓ message.action 383ms channel=telegram

Root Cause (if applicable)

  • Root cause: The Telegram send path treated a DM/private-topic message_thread_id failure as recoverable and retried without thread parameters, which converted a topic send into a plain DM send while still returning success.
  • Missing detection / guardrail: Tests covered the old threadless fallback behavior, so the wrong-surface success path was considered expected.
  • Contributing context (if known): Telegram Bot API behavior around DM topics changed around Bot API 10.0; current live behavior still rejects message_thread_id for this bot/topic, and direct_messages_topic_id has been reported to return HTTP 200 without reliable topic placement.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: extensions/telegram/src/bot/delivery.test.ts, extensions/telegram/src/send.test.ts, extensions/telegram/src/draft-stream.test.ts.
  • Scenario the test should lock in: DM-topic sends that Telegram rejects must not retry without the requested topic id and must not return success for wrong-surface delivery.
  • Why this is the smallest reliable guardrail: The bug is in Telegram outbound fallback behavior, so focused Telegram send/delivery tests cover the behavior without changing gateway or channel contracts.
  • Existing test that already covers this (if any): Existing Telegram delivery/send tests covered the old fallback path and were updated to lock the corrected behavior.
  • If no new test is added, why not: N/A.

User-visible / Behavior Changes

Telegram DM-topic send failures are now visible to users instead of being masked by a plain-DM fallback. A send to an affected topic may fail with Telegram's message thread not found error until Telegram accepts a valid topic parameter for that chat.

Diagram (if applicable)

Before:
Telegram topic send -> Telegram rejects thread id -> OpenClaw retries without thread -> plain DM delivered -> success returned

After:
Telegram topic send -> Telegram rejects thread id -> OpenClaw returns failure -> no silent wrong-surface delivery

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: Ubuntu workstation
  • Runtime/container: Node 22.22.0 via nvm, pnpm 10.33.2
  • Model/provider: N/A
  • Integration/channel (if any): Telegram, bot @tmimmanuel_openclaw_bot
  • Relevant config (redacted): Target chat 7116088418, topic id 42159

Steps

  1. Start gateway from synced main and send to Telegram target 7116088418 with --thread-id 42159.
  2. Observe main logs Telegram's message thread not found but still returns success after fallback.
  3. Start gateway from PR head dbec502085 and send the same command.
  4. Observe PR branch returns a message.action failure and CLI exit code 1 instead of silently retrying without topic.
  5. Run the focused Telegram checks listed below.

Expected

  • Main reproduces the masked failure: Telegram rejects the topic send, OpenClaw still returns success after threadless fallback.
  • PR branch does not mask the failure: Telegram rejects the topic send, OpenClaw returns an error and does not claim delivery success.

Actual

  • Main 50898c4a72: returned success with messageId: 15 while logging 400: Bad Request: message thread not found.
  • PR dbec502085: returned GatewayClientRequestError and exit code 1 with the same Telegram rejection.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Supplemental checks:

  • pnpm exec oxfmt --check --threads=1 CHANGELOG.md extensions/telegram/src/bot/delivery.send.ts extensions/telegram/src/bot/delivery.test.ts extensions/telegram/src/draft-stream.ts extensions/telegram/src/draft-stream.test.ts extensions/telegram/src/send.ts extensions/telegram/src/send.test.ts
  • pnpm test extensions/telegram/src/bot/delivery.test.ts extensions/telegram/src/draft-stream.test.ts extensions/telegram/src/send.test.ts -- --reporter=verbose
  • pnpm tsgo:extensions
  • pnpm check:changed

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: Live Telegram DM-topic send on synced main still logs Telegram message thread not found and returns success after fallback; live Telegram DM-topic send on PR head returns failure instead of masked success; gateway logs show message.action changes from success on main to failure on PR.
  • Edge cases checked: The tested path is a real Telegram bot/account/topic, not a mocked send. The PR keeps quote/formatting retry behavior separate from DM-topic threadless fallback.
  • What you did not verify: Successful Telegram delivery into the affected DM topic, because the Telegram API rejected the topic id during the live PR-head test; unrelated Telegram media/sticker send paths in live mode.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: Users affected by Telegram's DM-topic rejection will now see a send failure instead of receiving a message in the plain DM.
    • Mitigation: This is intentional: wrong-surface delivery is worse than a visible failure. The error now makes the Telegram API behavior explicit so users and maintainers can distinguish OpenClaw fallback behavior from Telegram topic-routing behavior.

@openclaw-barnacle openclaw-barnacle Bot added triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. cli CLI command changes size: S labels May 6, 2026
@clawsweeper

clawsweeper Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge.

Summary
The PR removes Telegram DM/direct-topic threadless fallback for delivery, draft previews, and message-tool sends while preserving message_thread_id, updating regression tests, and adding a changelog entry.

Reproducibility: yes. Source inspection shows current main builds DM topic sends with message_thread_id and retries without the topic after message thread not found; the linked issue adds live Telegram/OpenClaw evidence for that path.

Real behavior proof
Needs real behavior proof before merge: The current PR body only lists formatter/test/type/check commands; it needs redacted real Telegram/OpenClaw output, logs, terminal output, screenshot, or recording showing the after-fix topic behavior before merge. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, ask a maintainer to comment @clawsweeper re-review.

Next step before merge
Needs contributor-supplied real behavior proof before merge; automation cannot produce proof from the contributor's Telegram setup.

Security
Cleared: The diff is limited to Telegram plugin TypeScript, tests, and changelog text, with no dependency, workflow, permission, secret-handling, download, or execution-surface change.

Review details

Best possible solution:

Land the fail-closed Telegram plugin change once redacted live proof shows rejected DM topic IDs no longer fall back to plain DMs and accepted topic sends still stay in the intended topic.

Do we have a high-confidence way to reproduce the issue?

Yes. Source inspection shows current main builds DM topic sends with message_thread_id and retries without the topic after message thread not found; the linked issue adds live Telegram/OpenClaw evidence for that path.

Is this the best way to solve the issue?

Yes for the current PR direction, with proof still missing. Failing direct/private topic sends loudly while preserving message_thread_id is safer than a blanket direct_messages_topic_id swap because the Telegram contract and issue comments show those fields cover different chat types.

What I checked:

  • Current main masks DM topic rejection: On current main, DM-scoped Telegram delivery sets allowThreadlessRetry for scope: "dm", suppresses the first message thread not found error, strips message_thread_id, and retries as a plain DM. (extensions/telegram/src/bot/delivery.send.ts:71, 2bdb77472624)
  • Current main keeps DM topic message_thread_id: resolveTelegramThreadSpec classifies non-group threaded targets as scope: "dm", and buildTelegramThreadParams serializes positive DM thread IDs as message_thread_id. (extensions/telegram/src/bot/helpers.ts:266, 2bdb77472624)
  • PR removes the threadless retry: The PR deletes the DM thread-not-found retry in sendTelegramWithThreadFallback and adds an explicit allowThreadlessRetry guard in message-tool send paths. (extensions/telegram/src/send.ts:664, dbec50208564)
  • Related issue evidence changed the direction: The linked discussion includes live reports that direct_messages_topic_id can return HTTP 200 without placing the message in the requested topic, and a later comment says Telegram appears to have fixed the message_thread_id rejection.
  • Telegram contract distinguishes both fields: Telegram Bot API and @grammyjs/types@3.26.0 distinguish message_thread_id for forum/private-chat topic mode from direct_messages_topic_id for channel direct-message chats, supporting the PR's decision not to blanket-swap the field. (pnpm-lock.yaml:2428, 2bdb77472624)
  • Proof gate is still failing: GitHub check runs for the PR head show broad checks passing, but Real behavior proof completed with failure, and the current PR body lists only formatter/test/type/check commands rather than a real Telegram/OpenClaw run after the fix. (dbec50208564)

Likely related people:

  • obviyus: Assigned on this PR and recently maintained adjacent Telegram send/runtime code, including the current PR head commit and recent extensions/telegram/src/send.ts history. (role: recent maintainer; confidence: medium; commits: dbec50208564, b66cc66440a7; files: extensions/telegram/src/send.ts, extensions/telegram/src/bot/delivery.send.ts, extensions/telegram/src/draft-stream.ts)
  • sebslight: Merged work in Telegram: keep DM topic replies in the originating thread #18586 intentionally added DM-topic message_thread_id preservation and the related regression coverage shape. (role: introduced behavior; confidence: medium; commits: 0cff8bc4e697; files: extensions/telegram/src/bot/helpers.ts, extensions/telegram/src/bot/delivery.test.ts, extensions/telegram/src/draft-stream.test.ts)
  • steipete: Prior ClawSweeper history for the linked Telegram DM-topic issue points to recent maintainer work on the central Telegram helpers/docs around DM thread-session policy. (role: adjacent owner; confidence: medium; commits: 7db255150c27, a7d2953956ef, b8c0a1e9ff24; files: extensions/telegram/src/bot/helpers.ts, extensions/telegram/src/bot/helpers.test.ts, docs/channels/telegram.md)

Remaining risk / open question:

  • No contributor-supplied after-fix real Telegram/OpenClaw proof is present on the current PR head.
  • Telegram Bot API 10.0 behavior around private topics was externally unstable during the report, so live placement or fail-closed proof matters more than unit tests alone.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 2bdb77472624.

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed proof: sufficient ClawSweeper judged the real behavior proof convincing. triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 6, 2026
@tmimmanuel tmimmanuel marked this pull request as draft May 6, 2026 18:00
@tmimmanuel tmimmanuel marked this pull request as ready for review May 6, 2026 18:00
@tmimmanuel tmimmanuel force-pushed the fix/78463-stale-running-tasks branch from 539ba19 to 7badb8f Compare May 6, 2026 18:07
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@openclaw-barnacle openclaw-barnacle Bot added channel: telegram Channel integration: telegram size: M and removed cli CLI command changes size: S labels May 8, 2026
@tmimmanuel tmimmanuel changed the title fix(tasks): mark restart-interrupted tasks lost fix(telegram): send DM topics with direct topic id May 8, 2026
@openclaw-barnacle openclaw-barnacle Bot added triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. size: S size: M proof: supplied External PR includes structured after-fix real behavior proof. and removed proof: supplied External PR includes structured after-fix real behavior proof. proof: sufficient ClawSweeper judged the real behavior proof convincing. size: M size: S triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 8, 2026
@obviyus obviyus self-assigned this May 9, 2026
@obviyus obviyus force-pushed the fix/78463-stale-running-tasks branch from a4aaffa to dbec502 Compare May 9, 2026 03:20
@obviyus obviyus changed the title fix(telegram): send DM topics with direct topic id fix(telegram): fail DM topic sends without threadless retry May 9, 2026
@openclaw-barnacle openclaw-barnacle Bot added size: S triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. proof: supplied External PR includes structured after-fix real behavior proof. and removed size: M proof: supplied External PR includes structured after-fix real behavior proof. triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 9, 2026
@obviyus obviyus added the proof: override Maintainer override for the external PR real behavior proof gate. label May 9, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: supplied External PR includes structured after-fix real behavior proof. label May 9, 2026
@obviyus obviyus force-pushed the fix/78463-stale-running-tasks branch from dbec502 to 4af08d1 Compare May 9, 2026 03:35
@obviyus obviyus merged commit 7a2cc4b into openclaw:main May 9, 2026
101 checks passed
@obviyus

obviyus commented May 9, 2026

Copy link
Copy Markdown
Contributor

Landed via rebase onto main.

  • Scoped tests: pnpm test extensions/telegram/src/bot/delivery.test.ts extensions/telegram/src/draft-stream.test.ts extensions/telegram/src/send.test.ts -- --reporter=verbose; pnpm exec oxfmt --check --threads=1 CHANGELOG.md extensions/telegram/src/bot/delivery.send.ts extensions/telegram/src/bot/delivery.test.ts extensions/telegram/src/draft-stream.ts extensions/telegram/src/draft-stream.test.ts extensions/telegram/src/send.ts extensions/telegram/src/send.test.ts; pnpm tsgo:extensions; pnpm check:changed
  • Changelog: CHANGELOG.md updated
  • Land commit: 4af08d1f905c66b69cfbc5cfc64cb46508e1cc74
  • Merge commit: 7a2cc4b8d65c00eaab66771b9b5be33c3f1fe647

Thanks @tmimmanuel!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: telegram Channel integration: telegram proof: override Maintainer override for the external PR real behavior proof gate. size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Telegram DM topics now require direct_messages_topic_id; message_thread_id falls back to main DM

2 participants