Problem
BlueBubbles server replays old webhook events after restarts or reconnections. The OpenClaw BlueBubbles extension has no protection against this, causing duplicate message processing and duplicate outbound replies.
Incident (2026-02-08)
- BlueBubbles replayed webhooks from ~17 hours prior
- OpenClaw processed all of them as new messages
- Result: 11x duplicate intro messages sent to a family contact
Root Cause
processMessage() in extensions/bluebubbles/src/monitor.ts has:
- No GUID-based dedup — same
messageId can be processed multiple times across restarts
- No message age/staleness check — arbitrarily old messages are accepted as new
- The existing debouncer only coalesces rapid-fire events within a short window (text + attachment), not replays
- The reply cache (
blueBubblesReplyCacheByMessageId) is in-memory only — lost on restart
Suggested Fix
Add two guards at the top of processMessage():
-
Staleness check: Drop inbound messages with a timestamp older than N minutes (e.g., 5 min). Configurable via channels.bluebubbles.maxMessageAgeMs or similar.
-
GUID dedup: Track recently processed message GUIDs in a TTL'd Map (e.g., 30 min / 5K entries). Drop any message whose GUID was already processed.
Both should skip fromMe messages (those are just cached for reply context).
Workaround
We patched monitor.ts directly with both guards. Works but is overwritten on openclaw update.
Environment
- OpenClaw: latest (as of 2026-02-08)
- BlueBubbles: v1.9.9
- macOS (ARM)
- Node v25
Problem
BlueBubbles server replays old webhook events after restarts or reconnections. The OpenClaw BlueBubbles extension has no protection against this, causing duplicate message processing and duplicate outbound replies.
Incident (2026-02-08)
Root Cause
processMessage()inextensions/bluebubbles/src/monitor.tshas:messageIdcan be processed multiple times across restartsblueBubblesReplyCacheByMessageId) is in-memory only — lost on restartSuggested Fix
Add two guards at the top of
processMessage():Staleness check: Drop inbound messages with a timestamp older than N minutes (e.g., 5 min). Configurable via
channels.bluebubbles.maxMessageAgeMsor similar.GUID dedup: Track recently processed message GUIDs in a TTL'd Map (e.g., 30 min / 5K entries). Drop any message whose GUID was already processed.
Both should skip
fromMemessages (those are just cached for reply context).Workaround
We patched
monitor.tsdirectly with both guards. Works but is overwritten onopenclaw update.Environment