Skip to content

[Bug]: WhatsApp outbound self-sends make channels status report fresh inbound activity #79056

@bittoby

Description

@bittoby

Summary

When OpenClaw sends a WhatsApp message from the Gateway to the linked account's own WhatsApp number, openclaw channels status --json can report that WhatsApp inbound activity also advanced.

This makes channels status --probe / status JSON look like a real inbound WhatsApp message was handled even though the Gateway only performed an outbound send and the logs show no inbound message handling.

Environment

  • OS: Ubuntu 24.04
  • OpenClaw: current main at 95a1c91531
  • Runtime: Node 22
  • Gateway: managed systemd user service
  • Channel: WhatsApp Web, linked account default
  • Auth/config: live WhatsApp account, private phone numbers redacted

Reproduction

  1. Start a linked WhatsApp Gateway account and verify it is healthy.
OPENCLAW_HIDE_BANNER=1 openclaw channels status --probe
  1. Capture the current WhatsApp account status.
BEFORE="$(OPENCLAW_HIDE_BANNER=1 openclaw channels status --json)"
  1. Resolve the linked WhatsApp account's own E.164 number.
TARGET="$(
  OPENCLAW_HIDE_BANNER=1 openclaw gateway health --json \
    | node -e 'let s="";process.stdin.on("data",d=>s+=d);process.stdin.on("end",()=>{const j=JSON.parse(s); console.log(j.channels?.whatsapp?.self?.e164 || "")})'
)"
  1. Send one Gateway-originated WhatsApp message to that same number.
MARKER="OpenClaw WhatsApp inbound-status echo repro $(date -u +%Y%m%dT%H%M%SZ)"
SEND="$(OPENCLAW_HIDE_BANNER=1 openclaw message send --channel whatsapp --account default --target "$TARGET" --message "$MARKER" --json)"
sleep 8
AFTER="$(OPENCLAW_HIDE_BANNER=1 openclaw channels status --json)"
  1. Compare the WhatsApp account lastInboundAt and lastOutboundAt fields before/after.
node - <<'NODE' "$BEFORE" "$SEND" "$AFTER" "$MARKER"
const [beforeRaw, sendRaw, afterRaw, marker] = process.argv.slice(2);
const before = JSON.parse(beforeRaw);
const send = JSON.parse(sendRaw);
const after = JSON.parse(afterRaw);
function acct(j){ return j.channelAccounts?.whatsapp?.[0] ?? {}; }
function iso(ms){ return typeof ms === "number" ? new Date(ms).toISOString() : null; }
const b = acct(before);
const a = acct(after);
console.log(JSON.stringify({
  marker,
  sendMessageId: send.payload?.result?.messageId,
  before: { lastInboundAt: iso(b.lastInboundAt), lastOutboundAt: iso(b.lastOutboundAt) },
  after: { lastInboundAt: iso(a.lastInboundAt), lastOutboundAt: iso(a.lastOutboundAt) },
  inboundAdvanced: (a.lastInboundAt ?? 0) > (b.lastInboundAt ?? 0),
  outboundAdvanced: (a.lastOutboundAt ?? 0) > (b.lastOutboundAt ?? 0)
}, null, 2));
NODE

Expected behavior

For a Gateway-originated WhatsApp self-send:

  • lastOutboundAt should advance.
  • lastInboundAt should not advance unless a real inbound WhatsApp message is accepted and handled.
  • Logs should show an outbound send only.

Actual behavior

Both timestamps advanced for a single Gateway-originated self-send:

{
  "marker": "OpenClaw WhatsApp inbound-status echo repro 20260507T174110Z",
  "sendMessageId": "3EB03B031C04B624AAEA9B",
  "before": {
    "lastInboundAt": "2026-05-07T17:18:40.619Z",
    "lastOutboundAt": "2026-05-07T17:18:40.517Z"
  },
  "after": {
    "lastInboundAt": "2026-05-07T17:41:18.191Z",
    "lastOutboundAt": "2026-05-07T17:41:18.145Z"
  },
  "inboundAdvanced": true,
  "outboundAdvanced": true
}

The matching redacted Gateway logs showed only outbound send activity for the marker window:

[whatsapp] Sending message -> sha256:<redacted>
[whatsapp] Sent message 3EB03B031C04B624AAEA9B -> sha256:<redacted>
[ws] res send channel=whatsapp

No Inbound message, web-inbound, or web-auto-reply log line appeared for the marker.

Why this matters

openclaw channels status --probe and the status JSON are used as live channel-health and activity diagnostics. If outbound WhatsApp echoes update inbound activity, operators can misread an outbound-only send as proof that WhatsApp inbound handling is fresh and healthy.

Suspected area

This looks related to WhatsApp Web messages.upsert activity accounting versus outbound echo filtering. The status activity update should line up with accepted inbound-message handling, not raw WhatsApp Web events that later get discarded as echoes, stale history, failed enrichment, or duplicates.

Additional notes

  • This was reproduced with real WhatsApp Web, not only unit tests.
  • Phone numbers and JIDs are redacted.
  • I did not test multi-account WhatsApp or long-lived multi-day behavior.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions