openclaw - ✅(Solved) Fix [Bug]: WhatsApp media send silently dropped — legacy deps.whatsapp shim hijacks sendMedia → text-only fallback [2 pull requests, 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#63126Fetched 2026-04-09 07:58:10
View on GitHub
Comments
1
Participants
2
Timeline
6
Reactions
0
Timeline (top)
labeled ×2commented ×1cross-referenced ×1referenced ×1

openclaw message send --channel whatsapp --media <local-path> returns a successful messageId but the recipient never receives the attachment — only the text is delivered. Reproduces with both CLI and the agent message tool, with any local path (host-absolute, under allowed roots).

Error Message

Root cause (traced via console.error patches)

Root Cause

Root cause (traced via console.error patches)

Fix Action

Fix / Workaround

Root cause (traced via console.error patches)

Workaround / fix suggestion

In the sendMedia wrapper of createWhatsAppOutboundBase, bypass the legacy dep lookup and call sendMessageWhatsApp directly (or teach the legacy shim to honour mediaUrl). Patching the bundled file with:

PR fix notes

PR #63160: fix(whatsapp): bypass legacy dep shim in sendMedia to restore attachment delivery

Description (problem / solution / changelog)

Summary

  • Bypass legacy resolveOutboundSendDep in sendMedia — the legacy deps.whatsapp/sendWhatsApp shim pre-dates the media-aware signature and silently drops mediaUrl, causing all WhatsApp media sends (images, audio, documents) to arrive as text-only while reporting success
  • The sendText path still uses dep resolution for backwards compatibility; only sendMedia is changed
  • Added a regression test that verifies legacy deps are not called for media sends

Test plan

  • Existing outbound-base.test.ts tests pass (4/4)
  • New test sendMedia bypasses legacy deps and always calls sendMessageWhatsApp directly (#63126) confirms legacy shim is never invoked and mediaUrl reaches sendMessageWhatsApp
  • Manual verification: openclaw message send --channel whatsapp --media <file> delivers attachment to recipient

Fixes #63126

🤖 Generated with Claude Code

Changed files

  • extensions/whatsapp/src/outbound-base.test.ts (modified, +41/-0)
  • extensions/whatsapp/src/outbound-base.ts (modified, +5/-6)

PR #62474: fix(cli/send-runtime): route to sendMedia when media is present in createChannelOutboundRuntimeSend

Description (problem / solution / changelog)

Problem

createChannelOutboundRuntimeSend in src/cli/send-runtime/channel-outbound-send.ts always dispatched to outbound.sendText, ignoring opts.mediaUrl / opts.mediaUrls. Channel adapters (e.g. WhatsApp) expose sendText and sendMedia as separate functions — sendText does not accept or forward mediaUrl, so media was silently dropped while the CLI returned a successful messageId.

This affects both code paths that send messages:

  1. CLIopenclaw message send --media, openclaw message broadcast --media, etc.
  2. Gateway / agents — any agent using the message tool with media.

Regression introduced in the 2026.4.5 channel seam / outbound deps refactors. Worked correctly through 2026.4.2.

Fixes #62399.

Fix

  • Detect media presence via opts.mediaUrl or opts.mediaUrls (non-empty array)
  • Prefer outbound.sendMedia when media is detected and the adapter exposes it; fall back to outbound.sendText otherwise (text-only calls are unchanged)
  • Forward mediaUrls (array form) in addition to mediaUrl so multi-media sends are covered
  • Extend RuntimeSendOpts to type mediaUrls correctly

Testing

Verified locally against WhatsApp: openclaw message send --channel whatsapp --target "+34x" --message "test" --media /tmp/red.png now delivers both the text and the image. Gateway log shows hasMedia: true and the correct sendMedia path is invoked.

Changed files

  • src/cli/send-runtime/channel-outbound-send.ts (modified, +8/-2)

Code Example

openclaw message send --channel whatsapp --account default \
    --target +<number> --message "mp3 test" \
    --media /home/me/.openclaw/workspace/tmp/test.mp3 --json
  Result JSON includes mediaUrl + messageId, but WhatsApp receives
  text-only. Gateway log at sendMessageWhatsApp shows hasMedia:false.


### Expected behavior

Whatsapp receives voice media file.

### Actual behavior

Nothing happen

### OpenClaw version

2026.4.8

### Operating system

Ubuntu 24.04

### Install method

Install: `npm i -g openclaw`

### Model

openai-codex/gpt5.4

### Provider / routing chain

openclaw -> whatsapp

### Additional provider/model setup details

 Root cause (traced via console.error patches)

  In dist/send-Dw4UBtXk.js at the WhatsApp outbound adapter
  (createWhatsAppOutboundBase), both sendText and sendMedia wrappers
  route through:
  resolveOutboundSendDep(deps, "whatsapp",
    { legacyKeys: WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS }) ?? sendMessageWhatsApp

  The gateway runtime injects a legacy deps.whatsapp shim (visible as
  depKeys: ["discord","whatsapp","cron","sendDiscord","sendWhatsapp","sendCron"]).
  Because this shim pre-dates the media-aware signature, calling it from
  the sendMedia branch drops the mediaUrl and internally routes back
  through the text-only path. Observed trace:

  [waOutboundSendMedia]  mediaUrl=//test.mp3  usingLegacyDep=true
  [waOutboundSendText]   (deps absent on re-entry)
  [sendMessageWhatsApp]  optKeys=[verbose,cfg,accountId,gifPlayback]   ← no mediaUrl

  So the upstream deliverOutboundPayloadsCore correctly selects the
  media branch (supportsMedia: true, summaryMediaUrls: [...]), but the
  adapter re-routes into text-only inside the WhatsApp plugin.

  Workaround / fix suggestion

  In the sendMedia wrapper of createWhatsAppOutboundBase, bypass the
  legacy dep lookup and call sendMessageWhatsApp directly (or teach the
  legacy shim to honour mediaUrl). Patching the bundled file with:

  sendMedia: async ({ cfg, to, text, mediaUrl, mediaAccess,
                      mediaLocalRoots, mediaReadFile, accountId,
                      deps, gifPlayback }) => {
    return await sendMessageWhatsApp(to, normalizeText(text), {
      verbose: false, cfg, mediaUrl, mediaAccess, mediaLocalRoots,
      mediaReadFile, accountId: accountId ?? void 0, gifPlayback
    });
  }

  immediately restores media delivery (verified end-to-end: mp3 arrives on
  WhatsApp, (media) tag appears in outbound log, send takes ~1.8s vs
  ~240ms for text).

  The same resolveOutboundSendDep pattern exists in sendText — should
  likely be removed there too if the legacy shim path is no longer
  intended to be used, or the shim should be updated.

  Impact

  Any media send via WhatsApp (agent tool message, CLI message send,
  broadcast with --media) is silently text-only. Gateway returns success
  with a messageId, so upstream callers / agents cannot detect the loss.


### Logs, screenshots, and evidence
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

openclaw message send --channel whatsapp --media <local-path> returns a successful messageId but the recipient never receives the attachment — only the text is delivered. Reproduces with both CLI and the agent message tool, with any local path (host-absolute, under allowed roots).

Steps to reproduce

  openclaw message send --channel whatsapp --account default \
    --target +<number> --message "mp3 test" \
    --media /home/me/.openclaw/workspace/tmp/test.mp3 --json
  Result JSON includes mediaUrl + messageId, but WhatsApp receives
  text-only. Gateway log at sendMessageWhatsApp shows hasMedia:false.


### Expected behavior

Whatsapp receives voice media file.

### Actual behavior

Nothing happen

### OpenClaw version

2026.4.8

### Operating system

Ubuntu 24.04

### Install method

Install: `npm i -g openclaw`

### Model

openai-codex/gpt5.4

### Provider / routing chain

openclaw -> whatsapp

### Additional provider/model setup details

 Root cause (traced via console.error patches)

  In dist/send-Dw4UBtXk.js at the WhatsApp outbound adapter
  (createWhatsAppOutboundBase), both sendText and sendMedia wrappers
  route through:
  resolveOutboundSendDep(deps, "whatsapp",
    { legacyKeys: WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS }) ?? sendMessageWhatsApp

  The gateway runtime injects a legacy deps.whatsapp shim (visible as
  depKeys: ["discord","whatsapp","cron","sendDiscord","sendWhatsapp","sendCron"]).
  Because this shim pre-dates the media-aware signature, calling it from
  the sendMedia branch drops the mediaUrl and internally routes back
  through the text-only path. Observed trace:

  [waOutboundSendMedia]  mediaUrl=/…/test.mp3  usingLegacyDep=true
  [waOutboundSendText]   (deps absent on re-entry)
  [sendMessageWhatsApp]  optKeys=[verbose,cfg,accountId,gifPlayback]   ← no mediaUrl

  So the upstream deliverOutboundPayloadsCore correctly selects the
  media branch (supportsMedia: true, summaryMediaUrls: [...]), but the
  adapter re-routes into text-only inside the WhatsApp plugin.

  Workaround / fix suggestion

  In the sendMedia wrapper of createWhatsAppOutboundBase, bypass the
  legacy dep lookup and call sendMessageWhatsApp directly (or teach the
  legacy shim to honour mediaUrl). Patching the bundled file with:

  sendMedia: async ({ cfg, to, text, mediaUrl, mediaAccess,
                      mediaLocalRoots, mediaReadFile, accountId,
                      deps, gifPlayback }) => {
    return await sendMessageWhatsApp(to, normalizeText(text), {
      verbose: false, cfg, mediaUrl, mediaAccess, mediaLocalRoots,
      mediaReadFile, accountId: accountId ?? void 0, gifPlayback
    });
  }

  immediately restores media delivery (verified end-to-end: mp3 arrives on
  WhatsApp, (media) tag appears in outbound log, send takes ~1.8s vs
  ~240ms for text).

  The same resolveOutboundSendDep pattern exists in sendText — should
  likely be removed there too if the legacy shim path is no longer
  intended to be used, or the shim should be updated.

  Impact

  Any media send via WhatsApp (agent tool message, CLI message send,
  broadcast with --media) is silently text-only. Gateway returns success
  with a messageId, so upstream callers / agents cannot detect the loss.


### Logs, screenshots, and evidence

```shell

Impact and severity

No response

Additional information

No response

extent analysis

TL;DR

Bypass the legacy dependency lookup in the sendMedia wrapper of createWhatsAppOutboundBase to fix the issue with media files not being sent over WhatsApp.

Guidance

  • The issue is caused by the legacy dependency shim dropping the mediaUrl and routing back through the text-only path.
  • To fix this, update the sendMedia wrapper to call sendMessageWhatsApp directly, bypassing the legacy dependency lookup.
  • Verify the fix by checking if the media file is delivered successfully over WhatsApp and if the (media) tag appears in the outbound log.
  • Consider removing the resolveOutboundSendDep pattern from the sendText wrapper as well, or update the legacy shim to honor the mediaUrl.

Example

sendMedia: async ({ cfg, to, text, mediaUrl, mediaAccess, mediaLocalRoots, mediaReadFile, accountId, deps, gifPlayback }) => {
  return await sendMessageWhatsApp(to, normalizeText(text), {
    verbose: false, cfg, mediaUrl, mediaAccess, mediaLocalRoots, mediaReadFile, accountId: accountId ?? void 0, gifPlayback
  });
}

Notes

This fix assumes that the sendMessageWhatsApp function is capable of handling media files. If this is not the case, further modifications may be needed.

Recommendation

Apply the workaround by updating the sendMedia wrapper to call sendMessageWhatsApp directly, as this has been verified to restore media delivery.

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…

FAQ

Expected behavior

Whatsapp receives voice media file.

Still need to ship something?

×6

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

Back to top recommendations

TRENDING