openclaw - 💡(How to fix) Fix iMessage replays old DMs from iCloud sync as new inbound messages — missing since-rowid cursor on session init [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#72322Fetched 2026-04-27 05:31:35
View on GitHub
Comments
1
Participants
2
Timeline
2
Reactions
0
Author
Timeline (top)
closed ×1commented ×1

When the iMessage monitor starts (gateway restart, imsg RPC reconnect, or new session), old messages from the chat.db that were synced via iCloud get streamed as new inbound messages. This causes the agent to respond to conversations from months or years ago as if they were just received.

Root Cause

The imsg CLI supports --since-rowid for resuming from a specific point:

imsg watch --since-rowid <value>   start watching after this rowid

However, the iMessage monitor's watch.subscribe call does not pass a rowid cursor:

attemptSubscriptionId = (await attemptClient.request("watch.subscribe", { attachments: includeAttachments }, { timeoutMs: probeTimeoutMs }))?.subscription ?? null;
// No sinceRowid passed

This is the same root cause as #1647 (closed without fix) and related to #61445 (echo loop on restart).

When iCloud sync writes/updates old messages in chat.db, those changes trigger the imsg watch stream, and without a rowid fence, they flow in as "new" messages.

Fix Action

Workaround

Setting dmHistoryLimit: 0 in the iMessage channel config does NOT prevent this — that config controls group chat context, not inbound replay filtering.

The only current workaround is to sign the Mac out of iCloud Messages or use a separate Apple ID that doesn't sync historical messages.

Code Example

imsg watch --since-rowid <value>   start watching after this rowid

---

attemptSubscriptionId = (await attemptClient.request("watch.subscribe", { attachments: includeAttachments }, { timeoutMs: probeTimeoutMs }))?.subscription ?? null;
// No sinceRowid passed
RAW_BUFFERClick to expand / collapse

Summary

When the iMessage monitor starts (gateway restart, imsg RPC reconnect, or new session), old messages from the chat.db that were synced via iCloud get streamed as new inbound messages. This causes the agent to respond to conversations from months or years ago as if they were just received.

Reproduction

  1. Mac Mini signed into a family iCloud account ([email protected]) with iCloud Messages sync enabled
  2. chat.db contains ~63,000 messages across 141 contacts and 98 conversations (including messages from spouse, siblings, etc.)
  3. Gateway restarts or imsg RPC reconnects
  4. Old messages (some from 2024) appear as new inbound messages with was_mentioned: true metadata
  5. Agent responds to these old messages as if they were live DMs from the allowlisted sender

Observed Behavior

Three old messages were replayed as new inbound:

Message IDOriginal DateTextSender
2258Wed 2024-09-11 08:55 EDT"It's hard to say when she hasn't been feeling well for a while"+16107152757
4180Sun 2024-09-29 14:42 EDT"Mom has to go to the store?"+15162427814
52482Mon 2025-12-22 10:33 EST"How's Rosie doing?"+16107152757

These were messages from other people to the user, not from the allowlisted sender. But because they appeared in chat.db with was_mentioned: true, the bridge treated them as new inbound from +15166590526.

Additionally, garbled/corrupted messages were sent outbound on 2025-04-25 — likely related to the same root cause (stale DB entries being replayed).

Root Cause

The imsg CLI supports --since-rowid for resuming from a specific point:

imsg watch --since-rowid <value>   start watching after this rowid

However, the iMessage monitor's watch.subscribe call does not pass a rowid cursor:

attemptSubscriptionId = (await attemptClient.request("watch.subscribe", { attachments: includeAttachments }, { timeoutMs: probeTimeoutMs }))?.subscription ?? null;
// No sinceRowid passed

This is the same root cause as #1647 (closed without fix) and related to #61445 (echo loop on restart).

When iCloud sync writes/updates old messages in chat.db, those changes trigger the imsg watch stream, and without a rowid fence, they flow in as "new" messages.

Impact

  • Privacy concern: Messages from non-allowlisted contacts (spouse, siblings, etc.) get processed by the agent and can appear in session context
  • Confusion: Agent responds to old messages, user receives replies that make no sense
  • Trust: User sees responses referencing conversations they never had with the agent
  • Garbled output: Stale DB entries can cause corrupted outbound messages

Suggested Fix

  1. Persist the last processed rowid to disk (e.g., ~/.openclaw/state/imessage-cursor-{accountId}.json)
  2. On watch.subscribe, pass sinceRowid from the persisted cursor
  3. On first startup (no cursor exists), record max(rowid) from chat.db and skip all messages with rowid <= startup_max_rowid
  4. Update the cursor after each successfully processed inbound message

This is essentially the "Option 1 — Startup rowid fence" from #61445, applied to the DM/inbound path as well as the echo path.

Workaround

Setting dmHistoryLimit: 0 in the iMessage channel config does NOT prevent this — that config controls group chat context, not inbound replay filtering.

The only current workaround is to sign the Mac out of iCloud Messages or use a separate Apple ID that doesn't sync historical messages.

Environment

  • OpenClaw: 2026.4.21
  • macOS: Darwin 25.4.0 (arm64), Mac Mini M4
  • imsg: 0.5.0
  • Node: v24.14.1
  • iCloud account: family account with iCloud Messages sync enabled (~63K messages in chat.db)

extent analysis

TL;DR

The most likely fix is to persist the last processed rowid to disk and pass it to watch.subscribe to prevent old messages from being replayed as new inbound messages.

Guidance

  • To address the issue, implement the suggested fix by persisting the last processed rowid to disk, such as ~/.openclaw/state/imessage-cursor-{accountId}.json, and pass sinceRowid from the persisted cursor on watch.subscribe.
  • On first startup, record max(rowid) from chat.db and skip all messages with rowid <= startup_max_rowid to prevent old messages from being processed.
  • Update the cursor after each successfully processed inbound message to ensure that only new messages are processed.
  • Verify the fix by checking that old messages are no longer replayed as new inbound messages after a gateway restart or imsg RPC reconnect.

Example

// Persist the last processed rowid to disk
const cursorFile = `~/.openclaw/state/imessage-cursor-${accountId}.json`;
const cursor = await fs.readFile(cursorFile, 'utf8');
const sinceRowid = cursor ? JSON.parse(cursor).sinceRowid : null;

// Pass sinceRowid to watch.subscribe
attemptSubscriptionId = (await attemptClient.request("watch.subscribe", { 
  attachments: includeAttachments, 
  sinceRowid 
}, { timeoutMs: probeTimeoutMs }))?.subscription ?? null;

Notes

The suggested fix is based on the analysis of the issue and the provided code snippets. However, the implementation details may vary depending on the specific requirements and constraints of the project.

Recommendation

Apply the suggested fix by persisting the last processed rowid to disk and passing it to watch.subscribe to prevent old messages from being replayed as new inbound messages. This fix addresses the root cause of the issue and provides a reliable solution to prevent old messages from being processed as new inbound messages

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 iMessage replays old DMs from iCloud sync as new inbound messages — missing since-rowid cursor on session init [1 comments, 2 participants]