openclaw - 💡(How to fix) Fix WhatsApp proactive send fails: bundler duplicates active-listener.ts Map across chunks [3 comments, 4 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#49463Fetched 2026-04-08 00:55:01
View on GitHub
Comments
3
Participants
4
Timeline
5
Reactions
0
Timeline (top)
commented ×3closed ×1locked ×1

WhatsApp proactive outbound sends (via openclaw message send CLI or gateway RPC) always fail with:

Error: No active WhatsApp Web listener (account: default)

...even though WhatsApp is connected, linked, and listening for inbound messages.

Error Message

Error: No active WhatsApp Web listener (account: default)

Root Cause

The Rolldown bundler inlines src/web/active-listener.ts into multiple chunks, each with its own const listeners = new Map(). At runtime in the gateway process:

  1. model-selection-*.js chunk — contains setActiveWebListener() called by web-*.js during WhatsApp provider startup → writes to Map A
  2. auth-profiles-*.js chunk — contains requireActiveWebListener() used by the gateway RPC send handler → reads from Map B
  3. reply-*.js chunk — contains another requireActiveWebListener() used by outbound adapter chunks → reads from Map C

Maps A, B, and C are separate new Map() instances. The listener is set in Map A, but send operations check Maps B and C — which are always empty.

Fix Action

Workaround

Patched setActiveWebListener to also publish via globalThis.__ocWebListeners, and patched requireActiveWebListener in all chunks to check this global fallback. Full patch script available.

Code Example

Error: No active WhatsApp Web listener (account: default)

---

gateway RPC 'send'deliverOutboundPayloads (auth-profiles chunk)
  → createChannelHandler → loadChannelOutboundAdapter → outbound chunk
requireActiveWebListener() → checks reply chunk's MapEMPTY

WhatsApp startup → web-*.jssetActiveWebListener()
  → writes to model-selection chunk's MapNEVER READ by send path
RAW_BUFFERClick to expand / collapse

Bug Report

Summary

WhatsApp proactive outbound sends (via openclaw message send CLI or gateway RPC) always fail with:

Error: No active WhatsApp Web listener (account: default)

...even though WhatsApp is connected, linked, and listening for inbound messages.

Root Cause

The Rolldown bundler inlines src/web/active-listener.ts into multiple chunks, each with its own const listeners = new Map(). At runtime in the gateway process:

  1. model-selection-*.js chunk — contains setActiveWebListener() called by web-*.js during WhatsApp provider startup → writes to Map A
  2. auth-profiles-*.js chunk — contains requireActiveWebListener() used by the gateway RPC send handler → reads from Map B
  3. reply-*.js chunk — contains another requireActiveWebListener() used by outbound adapter chunks → reads from Map C

Maps A, B, and C are separate new Map() instances. The listener is set in Map A, but send operations check Maps B and C — which are always empty.

Affected Code Path

gateway RPC 'send' → deliverOutboundPayloads (auth-profiles chunk)
  → createChannelHandler → loadChannelOutboundAdapter → outbound chunk
    → requireActiveWebListener() → checks reply chunk's Map → EMPTY

WhatsApp startup → web-*.js → setActiveWebListener()
  → writes to model-selection chunk's Map → NEVER READ by send path

Why Inbound Works

Inbound message replies work because the reply path has a direct reference to the WebSocket connection object from the inbound handler — it doesn't need to look up the listener from the Map.

Environment

  • OpenClaw: 2026.3.13 (61d171a)
  • Node: v22.22.0
  • OS: Ubuntu (Vultr VPS)
  • Channel: WhatsApp only

Reproduction

  1. Install OpenClaw 2026.3.13 fresh on a new VPS
  2. Link WhatsApp
  3. Verify openclaw channels status shows connected
  4. Try openclaw message send --channel whatsapp --target +1234567890 --message test
  5. Observe: fails with 'No active WhatsApp Web listener'

Note: This may not reproduce on all installs. It appears to depend on which channel-web-*.js variant gets loaded at runtime. On some installs, channel-web-BZO9MGfW.js (imports from reply chunk) is used and the Maps align. On affected installs, channel-web-CnBLwZJB.js (imports from auth-profiles chunk) is used and they diverge.

Workaround

Patched setActiveWebListener to also publish via globalThis.__ocWebListeners, and patched requireActiveWebListener in all chunks to check this global fallback. Full patch script available.

Suggested Fix

Make active-listener.ts a proper shared singleton — either:

  1. Use a shared chunk that all other chunks import from (prevent inlining)
  2. Use globalThis for the listeners Map in the source code
  3. Configure the bundler to treat active-listener.ts as a shared module

extent analysis

Fix Plan

To resolve the issue, we will make active-listener.ts a proper shared singleton. We'll use the first suggested approach: creating a shared chunk that all other chunks import from to prevent inlining.

Step-by-Step Solution:

  1. Create a shared chunk:

    • Identify the active-listener.ts file and ensure it's not inlined by the Rolldown bundler.
    • Configure the bundler to treat active-listener.ts as a shared module.
  2. Modify active-listener.ts:

    • Ensure the listeners Map is defined and exported as a singleton.
    • Example:
      // active-listener.ts
      export const listeners = new Map();
      export function setActiveWebListener(listener) {
        listeners.set('default', listener);
      }
      export function requireActiveWebListener() {
        return listeners.get('default');
      }
  3. Update dependent chunks:

    • In model-selection-*.js, auth-profiles-*.js, and reply-*.js, import the active-listener.ts functions.
    • Use the imported functions to interact with the shared listeners Map.
    • Example:
      // model-selection-*.js
      import { setActiveWebListener } from './active-listener';
      // ...
      setActiveWebListener(webListener);
      // auth-profiles-*.js and reply-*.js
      import { requireActiveWebListener } from './active-listener';
      // ...
      const webListener = requireActiveWebListener();

Verification

  • After applying the fix, restart the OpenClaw service.
  • Verify that openclaw channels status shows WhatsApp as connected.
  • Test sending a message using openclaw message send --channel whatsapp --target +1234567890 --message test.
  • The message should be sent successfully without the 'No active WhatsApp Web listener' error.

Extra Tips

  • Ensure the bundler configuration is correct to prevent inlining of the active-listener.ts file.
  • Test the fix thoroughly to ensure it resolves the issue in all scenarios.
  • Consider implementing additional logging or monitoring to detect similar issues in the future.

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 WhatsApp proactive send fails: bundler duplicates active-listener.ts Map across chunks [3 comments, 4 participants]