Skip to content

iMessage plugin: self-echo infinite loop in DM chats (isSelfChat false positive) #61543

Description

@quriustus

Version

OpenClaw 2026.4.2 (d74a122)
macOS 26.3.1 (arm64), imsg via Homebrew

Summary

The iMessage plugin's isSelfChat heuristic false-positives on all DM chats, causing outbound messages to sometimes bypass the "from me" drop filter and leak back as inbound messages. This creates an infinite self-echo loop.

Reproduction

  1. Have an iMessage DM chat with contact +1234567890
  2. The chat's identifier in Messages.app DB is +1234567890
  3. Send a reply via OpenClaw
  4. imsg watch picks up the new DB row with is_from_me: true, sender: "+1234567890"
  5. Plugin evaluates normalizeIMessageHandle(sender) === normalizeIMessageHandle(chatIdentifier)true
  6. Instead of return { kind: "drop", reason: "from me" }, enters echo-cache path
  7. Echo cache misses (encoding artifacts from Messages.app attributed string storage corrupt the text)
  8. Message leaks through as inbound → generates reply → infinite loop

Root Cause

In monitor-provider-BaCJr_L0.js around line 917:

if (params.message.is_from_me) {
    params.selfChatCache?.remember(selfChatLookup);
    if (isSelfChat) {
        // Echo cache detection (designed for "Notes to Self" chats)
        // FALSE POSITIVE: in a DM, chatIdentifier IS the peer's handle,
        // and imsg reports sender as the peer's handle for outbound too
    } else {
        return { kind: "drop", reason: "from me" };  // correct path, never reached in DMs
    }
}

The isSelfChat check:

const isSelfChat = !isGroup && chatIdentifier != null 
    && normalizeIMessageHandle(sender) === normalizeIMessageHandle(chatIdentifier);

This is always true for DM outbound messages because imsg reports sender = peer handle = chatIdentifier.

Echo Cache Failure Mode

The echo cache compares exact text, but round-tripped messages have:

  • Binary encoding artifacts (attributed string metadata bytes decoded as UTF-8)
  • Possible text chunking differences
  • The garbled prefixes (\xef\xbf\xbd, \x01, etc.) guarantee no match

Observed Impact

  • ~20+ rapid-fire self-echo messages in a single DM
  • Session transcript polluted with 295 lines of echo garbage
  • Required manual session reset + gateway restart

Suggested Fixes

  1. Simplest: For is_from_me=true in non-group, non-actual-self chats, always drop. Detect actual self-chat by comparing against the Mac's own registered handles rather than chatIdentifier.
  2. Alternative: Use message GUID tracking for echo detection instead of text comparison.
  3. Defense in depth: Add a rate limiter — if >N replies to the same chat in <M seconds, pause and flag.

Workaround

Reset the poisoned session transcript (archive the .jsonl, keep header line only, restart gateway).
The echo loop stops once the accumulated garbage is cleared, but can recur on any DM.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions