Skip to content

[Bug]: Single WhatsApp media reply is sent twice in 2026.4.15 #68056

Description

@0xVespertine

Bug type

Regression (worked before, now fails)

Beta release blocker

No

Summary

On OpenClaw 2026.4.15, one WhatsApp request that yields one media reply results in two media replies being sent to the same conversation.

Steps to reproduce

  1. Start OpenClaw 2026.4.15 with WhatsApp enabled and channels.whatsapp.blockStreaming: false.
  2. Send one WhatsApp request that produces a single media response, for example a chart image.
  3. Observe that the agent sends two media replies for that one request to the same DM or group conversation.
  4. Confirm two outbound files are staged under ~/.openclaw/media/outbound/ within the same second for the single request.
  5. Confirm gateway logs contain two Sent media reply lines for the same conversation within the same second.

Expected behavior

One request that produces one media response should result in exactly one outbound media file and exactly one WhatsApp media reply.

Actual behavior

One WhatsApp request that yields one media response produces two outbound media files and two WhatsApp media replies to the same conversation a few hundred milliseconds apart.

OpenClaw version

2026.4.15 (041266a)

Operating system

Ubuntu Server 24.04

Install method

npm global

Model

openai-codex/gpt-5.4

Provider / routing chain

openclaw -> openai

Additional provider/model setup details

The affected agent config sets `agents.defaults.model.primary` to `openai-codex/gpt-5.4` and uses the `openai-codex` auth profile in OAuth mode. No additional provider routing relevant to the reproduction was identified in the local agent config.

Logs, screenshots, and evidence

Additional evidence: a temporary instrumentation of `resolveOutboundAttachmentFromUrl` (logging `new Error().stack` on each call, subsequently reverted) captured two distinct call stacks for the same mediaUrl on a single reply.

Stack 1:

resolveOutboundAttachmentFromUrl (outbound-attachment-Dc2tDWj8.js:6:54)
persistLocalReplyMedia            (reply-media-paths.runtime-B671n_FS.js:84:26)
normalizeMediaSource              (reply-media-paths.runtime-B671n_FS.js:117:16)
Object.normalizeMediaPaths        (reply-media-paths.runtime-B671n_FS.js:127:18)
Object.onBlockReply               (agent-runner.runtime-CTlghBhJ.js:217:63)


Stack 2 (~190 ms later, same request, same mediaUrl):

resolveOutboundAttachmentFromUrl (outbound-attachment-Dc2tDWj8.js:6:54)
persistLocalReplyMedia            (reply-media-paths.runtime-B671n_FS.js:84:26)
normalizeMediaSource              (reply-media-paths.runtime-B671n_FS.js:117:16)
Object.normalizeMediaPaths        (reply-media-paths.runtime-B671n_FS.js:127:18)
normalizeReplyPayloadMedia        (agent-runner.runtime-CTlghBhJ.js:1631:10)
buildReplyPayloads                (agent-runner.runtime-CTlghBhJ.js:1704:10)
async Promise.all (index 0)


Both stacks terminate at `resolveOutboundAttachmentFromUrl`, which calls `saveMediaBuffer(..., "outbound", ...)` and generates a fresh UUID per call. The two call sites create separate normalizer instances whose `persistedMediaBySource` caches are not shared; the identical input path therefore does not deduplicate across them, and each persists a separate outbound copy.

Stack 1 originates from `onBlockReply` despite `channels.whatsapp.blockStreaming: false` and `agents.defaults.blockStreamingDefault: "off"` in the active config.

Impact and severity

Affected users/systems/channels:
WhatsApp DM and WhatsApp group conversations on OpenClaw 2026.4.15.

Severity:
Medium. The agent responds, but every single-media reply is duplicated to the end user.

Frequency:
Observed repeatedly for the affected media-reply workflow in both DM and group tests.

Consequence:
Users receive duplicated chart/media messages for one request, which creates visible noise and reduces trust in the agent's output.

Additional information

Local agent-side checks did not identify a repo-level cause. The affected config still used tools.alsoAllow: ["message"], did not deny group:media or group:openclaw, and had channels.whatsapp.blockStreaming: false.

Additional debugging against the 2026.4.15 bundle suggests the duplicate is upstream in reply-media handling. For the affected reply, the final assistant output contained one MEDIA:<path> token once, but reply-media normalization appears to run through two paths for the same reply. Each path can stage the same media into outbound separately, producing two UUID files and two WhatsApp sends a few hundred milliseconds apart.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions