openclaw - 💡(How to fix) Fix Define durable final fallback delivery semantics across channels

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Error Message

OpenClaw has several user-visible failure modes where an agent turn ends with a sanitized fallback/error message internally, but the user sees silence because the channel delivery layer suppresses, drops, or cannot prove delivery of the final payload.

  • #60812: extend user-visible error fallback to Discord, Slack, Signal, WhatsApp.
  • #60830: detect empty provider responses as failures and improve Telegram error routing.
  • #84602: surface user-visible error when embedded session is stuck or overflows context.
  • #86395: Discord progress draft is deleted after final error reply.
  1. ReplyPayload.isError === true means user-visible error/fallback classification. It must not mean automatic suppression.
  • failed, with failure stage and error

Root Cause

OpenClaw has several user-visible failure modes where an agent turn ends with a sanitized fallback/error message internally, but the user sees silence because the channel delivery layer suppresses, drops, or cannot prove delivery of the final payload.

Fix Action

Fix / Workaround

  • #84569: WhatsApp long model call ends with payloads=0 and no reply.
  • #84578: narrow WhatsApp fix for final isError delivery.
  • #60812: extend user-visible error fallback to Discord, Slack, Signal, WhatsApp.
  • #63025: avoid silent completion when dispatch produces no sendable reply.
  • #60830: detect empty provider responses as failures and improve Telegram error routing.

#84578 can be treated as the immediate WhatsApp compliance patch, but the long-term fix should not be framed around WhatsApp. WhatsApp is one proving case for the shared durable final text contract.

RAW_BUFFERClick to expand / collapse

Problem

OpenClaw has several user-visible failure modes where an agent turn ends with a sanitized fallback/error message internally, but the user sees silence because the channel delivery layer suppresses, drops, or cannot prove delivery of the final payload.

The current WhatsApp report in #84569 is one concrete example: the embedded runner can produce a safe final isError: true payload for an incomplete turn, but the WhatsApp delivery path suppresses it. The same product problem shows up in related channel and recovery issues: final user-visible work exists, or should exist, but delivery status is ambiguous or absent.

This should be solved as a core channel contract:

If core emits a sanitized final fallback message, every durable text-capable channel must either deliver it or report a real delivery failure. It must not silently suppress it.

Related issues and PRs

Directly related:

  • #84569: WhatsApp long model call ends with payloads=0 and no reply.
  • #84578: narrow WhatsApp fix for final isError delivery.
  • #60812: extend user-visible error fallback to Discord, Slack, Signal, WhatsApp.
  • #63025: avoid silent completion when dispatch produces no sendable reply.
  • #60830: detect empty provider responses as failures and improve Telegram error routing.

Delivery and receipt semantics:

  • #77205: durable message lifecycle foundation.
  • #80749: Slack requires delivery receipts for replies.
  • #79811: avoid delivered status for empty outbound receipts.
  • #84078: Slack message_tool_only source replies fail because durable send requires reconcile support.

Session and recovery surfaces:

  • #84602: surface user-visible error when embedded session is stuck or overflows context.
  • #87028: recover orphaned session activity.
  • #85232: recover idle queues with stale model activity.
  • #86089: deliver restart recovery replies.
  • #77883: restart recovery can finish with payloads=0.

Other related silent/lost delivery reports:

  • #80520: Telegram messages silently dropped, no sendMessage logged.
  • #85520: Telegram real reply intermittently never sent; progress draft deletes anyway.
  • #83165: Slack long-running runs can appear silent when media delivery partially fails and recovery refuses replay.
  • #80715: Slack replies composed in transcript but never posted.
  • #86395: Discord progress draft is deleted after final error reply.

Desired contract

Core should define and test these rules:

  1. ReplyPayload.isError === true means user-visible error/fallback classification. It must not mean automatic suppression.
  2. A sanitized final fallback is deliverable text when the channel declares durable final text support.
  3. Hidden artifacts may still be suppressed: reasoning, compaction notices, non-final tool/progress errors, hook-cancelled payloads, and payloads that sanitize to empty.
  4. A visible final payload must finish with an explicit status:
    • sent, with platform identity or receipt
    • failed, with failure stage and error
    • partial_failed, if earlier payloads were sent and a later payload failed
    • suppressed, only when suppression is intentional and has a reason
  5. Empty platform identity such as messageId: "" must not be treated as successful delivery for visible final text.
  6. Delivery outcomes must be visible to recovery/diagnostics so heartbeat/session recovery can tell the difference between delivered, suppressed, failed, and platform-outcome-unknown.

Implementation plan

  1. Clarify the SDK/channel contract around isError, durable final text, and visible fallback delivery.

    Likely surfaces:

    • src/auto-reply/reply-payload.ts
    • src/channels/plugins/outbound.types.ts
    • src/channels/message/types.ts
    • src/plugin-sdk/channel-outbound.ts
  2. Tighten core durable delivery semantics.

    Likely surfaces:

    • src/infra/outbound/deliver.ts
    • src/infra/outbound/deliver-types.ts
    • src/channels/message/send.ts

    Core should not let a visible final fallback disappear as a no-op result.

  3. Make final fallback classification explicit enough that channels do not infer policy from isError alone.

    The important distinction is:

    • final user-visible fallback
    • normal final answer
    • non-final progress/tool/block payload
    • hidden/system artifact
  4. Audit bundled channel adapters for isError suppression or empty-identity delivery results.

    Known starting points include WhatsApp, Telegram, Slack, Discord, Signal, Feishu, and Matrix.

  5. Revisit sendTextOnlyErrorPayloads.

    This should either be removed, narrowed to “adapter needs full payload context,” or guarded so routing through sendPayload cannot silently drop final visible fallback text.

  6. Add general tests before channel-specific tests.

    Core tests should prove:

    • incomplete/empty model turn creates sanitized final fallback
    • raw provider JSON, request IDs, stacks, and partial aborted text do not leak
    • final isError: true text is delivered on a durable text channel
    • empty identity for visible final text is not counted as delivered
    • hidden/non-final payloads can still be suppressed with explicit reason
    • recovery/diagnostics can inspect the outcome
  7. Add cross-channel conformance coverage.

    For channels declaring durable final text support, prove:

    • normal final text delivers
    • sanitized final fallback delivers
    • empty sanitized text suppresses with reason
    • non-final tool/progress errors can remain suppressed
    • delivery result includes platform identity or receipt when sent
  8. Bring channel adapters into compliance.

    #84578 can be treated as the immediate WhatsApp compliance patch, but the long-term fix should not be framed around WhatsApp. WhatsApp is one proving case for the shared durable final text contract.

  9. Add observability.

    Session/diagnostic state should expose at least:

    • final fallback emitted
    • delivery sent
    • delivery suppressed with reason
    • delivery failed
    • platform outcome unknown

Non-goals

  • Do not add per-channel config like sendErrorPayloads for this behavior. Delivering safe final fallback text should be the product default.
  • Do not expose raw provider/internal errors to users.
  • Do not make every isError payload visible; non-final tool/progress/internal payloads may still be hidden.
  • Do not count empty message IDs or empty receipts as successful visible delivery.

Acceptance proof

This should not be considered production-ready until there is:

  • core unit coverage for sanitized fallback creation
  • core delivery coverage for visible final fallback semantics
  • cross-channel durable final text conformance coverage
  • channel-specific regression tests for at least WhatsApp, Telegram, Slack, and Discord where relevant
  • live proof on at least one real channel
  • for #84569 specifically, live WhatsApp plus long model/fallback proof when credentials and the vLLM environment are available

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING