openclaw - 💡(How to fix) Fix Bug: WhatsApp auto-reply delivery double-fires (deliverWebReply called 2x for same correlationId via dispatchReplyWithBufferedBlockDispatcher) [1 comments, 2 participants]

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…
GitHub stats
openclaw/openclaw#76112Fetched 2026-05-03 04:42:10
View on GitHub
Comments
1
Participants
2
Timeline
6
Reactions
2
Timeline (top)
mentioned ×2subscribed ×2commented ×1unsubscribed ×1

Root Cause

Hypothesized Root Cause

Fix Action

Fix / Workaround

  • File: dist/extensions/whatsapp/monitor-Cd6tuzSy.js
  • Logger call site: line 1835 (replyLogger.info(logPayload, "auto-reply sent (text)"))
  • Hot path: dispatchWhatsAppBufferedReply → calls dispatchReplyWithBufferedBlockDispatcher (imported from openclaw/plugin-sdk/reply-runtime) at line ~2073
  • dispatcherOptions.deliver callback (line ~2095) is invoked twice with the same payload, calling params.deliverReply (= deliverWebReply) on each invocation

dispatchReplyWithBufferedBlockDispatcher (in @openclaw/plugin-sdk/reply-runtime) emits two payloads for the same message:

  1. one normal block payload
  2. one queuedFinal flush payload that duplicates content
  • blockStreaming chunking patch (descarted in community trial — short messages also duplicate, ruling out chunking as sole cause)
  • Plugin restart / gateway restart (deterministic bug returns immediately)
  • Disabling block streaming via cfg

Code Example

2026-05-02T01:13:57.689-03:00  auto-reply sent (text)  corr=3A4AB775701E6033C3AA  durationMs=2476  text="[MAX] Confirmado..."
2026-05-02T01:13:57.705-03:00  auto-reply sent (text)  corr=3A4AB775701E6033C3AA  durationMs=14    text="[MAX] Confirmado..."
                                                                                  ^^                ^^^^^^^^^^^^^^^^^^^^
                                                                            duplicata 16ms        texto idêntico
RAW_BUFFERClick to expand / collapse

Bug Description

Determinístico double-fire of deliverWebReply in WhatsApp plugin: every outbound auto-reply is sent twice to the same recipient with the same correlationId, runId, and connectionId within 5–21 ms. 100% of recent auto-replies in DM (1:1) sessions are duplicated.

This is distinct from the Android-companion forwarding scenario in #48516 — here both deliveries originate from the same plugin path (Baileys WA provider, no node session, no Android app forwarding). Same correlationId in both delivery log entries.

Steps to Reproduce

  1. Pair WhatsApp via Baileys provider (DM 1:1 to self, selfChatMode: true)
  2. Send any message that triggers an auto-reply
  3. Observe two auto-replies in the chat with identical text, sent ~10 ms apart
  4. Inspect /tmp/openclaw/openclaw-YYYY-MM-DD.log — two auto-reply sent (text) entries with same correlationId

What Happens

Same runId + connectionId + correlationId are logged twice for one inbound message:

2026-05-02T01:13:57.689-03:00  auto-reply sent (text)  corr=3A4AB775701E6033C3AA  durationMs=2476  text="[MAX] Confirmado..."
2026-05-02T01:13:57.705-03:00  auto-reply sent (text)  corr=3A4AB775701E6033C3AA  durationMs=14    text="[MAX] Confirmado..."
                                                                                  ^^                ^^^^^^^^^^^^^^^^^^^^
                                                                            duplicata 16ms        texto idêntico

durationMs pattern is consistent across many samples:

  • 1st delivery: 200–2500 ms (real LLM-generated response)
  • 2nd delivery: 5–21 ms (cached/duplicate emission)

Both deliveries have providerAccepted: true from WhatsApp (WhatsApp Web accepts both).

Localization (Bundled JS Surface)

  • File: dist/extensions/whatsapp/monitor-Cd6tuzSy.js
  • Logger call site: line 1835 (replyLogger.info(logPayload, "auto-reply sent (text)"))
  • Hot path: dispatchWhatsAppBufferedReply → calls dispatchReplyWithBufferedBlockDispatcher (imported from openclaw/plugin-sdk/reply-runtime) at line ~2073
  • dispatcherOptions.deliver callback (line ~2095) is invoked twice with the same payload, calling params.deliverReply (= deliverWebReply) on each invocation

Hypothesized Root Cause

dispatchReplyWithBufferedBlockDispatcher (in @openclaw/plugin-sdk/reply-runtime) emits two payloads for the same message:

  1. one normal block payload
  2. one queuedFinal flush payload that duplicates content

Both routed through the same deliver callback → both reach deliverWebReply → both call msg.reply() on Baileys → 2 messages sent.

disableBlockStreaming config does not prevent this (already tested by another community member and reverted).

What Did Not Help

  • blockStreaming chunking patch (descarted in community trial — short messages also duplicate, ruling out chunking as sole cause)
  • Plugin restart / gateway restart (deterministic bug returns immediately)
  • Disabling block streaming via cfg

Affected Configuration

  • WhatsApp DM 1:1 (selfChatMode: true, recipient = self)
  • Group messages: not extensively tested in this scenario, but #48516 reports related but distinct group-routing duplicates via Android companion (different code path)

Expected Behavior

One inbound message → one outbound auto-reply (per intended chunk count).

Environment

  • OpenClaw gateway: 2026.4.29 (verified latest on npm at time of report)
  • Plugin runtime: ~/.openclaw/plugin-runtime-deps/openclaw-2026.4.29-da6bdffc3d96
  • Node: v25.9.0 (engines: >=22.14.0 — well above minimum)
  • Platform: macOS (darwin, arm64)
  • Channel: WhatsApp via Baileys WA provider, paired via QR
  • Pattern: 100% deterministic — every recent auto-reply duplicated

Observed Timeline

  • First duplicate observed in operator's log: 2026-04-02 (in v2026.4.x — earlier version had 3× sends per message; current behaviour is 2×, suggesting partial mitigation already shipped between v2026.4.x earlier versions and v2026.4.29)
  • Bug active and deterministic in v2026.4.29

Impact

  • Cosmetic: every WhatsApp auto-reply duplicated visually in chat
  • Cost: duplicate inference is not triggered (LLM only generates once — only delivery duplicates), but extra Baileys send call wastes a small amount of WhatsApp Web socket throughput
  • UX: confuses operator's WhatsApp client with redundant messages
  • Determinism: predictable, easily reproducible

Workarounds Considered Locally and Rejected

  1. Plugin hook message_sending — does not fire in this auto-reply path
  2. Plugin hook reply_dispatch — too high-level (cancels everything)
  3. CommonJS preload script — bundle uses ESM imports, immutable at runtime
  4. Direct bundle patching — violates upstream-trust principle, breaks on next update
  5. --experimental-loader — viable but high implementation cost and stability risk for primary user-facing channel

Suggested Fix Direction

  1. In dispatchReplyWithBufferedBlockDispatcher, deduplicate deliver invocations by (payload.text || payload.mediaUrl) + msg.id within the dispatcher
  2. Or: ensure queuedFinal flush does not re-emit content that was already delivered as a normal block
  3. Or: surface a config flag to opt out of queuedFinal re-emission

References

  • Related but distinct: #48516 (Android companion forwarding — different cause)
  • Related double-send patterns in other channels (already fixed): #71083 (Slack), #60645 (Slack/Telegram lane duplicate)

Reporter Note

Diagnostic done over multiple read-only sessions in May 2026; full evidence logs and timeline available locally. Happy to share gateway logs (PII-stripped) on request.

extent analysis

TL;DR

The most likely fix involves modifying the dispatchReplyWithBufferedBlockDispatcher function to deduplicate deliver invocations based on the payload content and message ID.

Guidance

  1. Investigate the dispatchReplyWithBufferedBlockDispatcher function: Verify that it indeed emits two payloads for the same message, causing the duplication.
  2. Implement deduplication logic: Modify the function to check for duplicate payloads based on (payload.text || payload.mediaUrl) + msg.id before invoking the deliver callback.
  3. Test the fix: Validate that the modification resolves the duplication issue without introducing new problems.
  4. Consider adding a config flag: Allow users to opt out of queuedFinal re-emission if needed, providing flexibility in handling different scenarios.

Example

// Pseudo-code example of deduplication logic
const deliveredPayloads = new Set();
function dispatchReplyWithBufferedBlockDispatcher(payload, msg) {
  const payloadKey = (payload.text || payload.mediaUrl) + msg.id;
  if (deliveredPayloads.has(payloadKey)) {
    return; // Skip duplicate payload
  }
  deliveredPayloads.add(payloadKey);
  // Proceed with delivering the payload
  dispatcherOptions.deliver(payload, msg);
}

Notes

The provided solution direction assumes that the dispatchReplyWithBufferedBlockDispatcher function is the root cause of the issue. However, further investigation may be necessary to confirm this.

Recommendation

Apply the workaround by modifying the dispatchReplyWithBufferedBlockDispatcher function to deduplicate deliver invocations, as this approach directly addresses the reported issue.

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

openclaw - 💡(How to fix) Fix Bug: WhatsApp auto-reply delivery double-fires (deliverWebReply called 2x for same correlationId via dispatchReplyWithBufferedBlockDispatcher) [1 comments, 2 participants]