troubleshooting.md
September 13, 2026 · View on GitHub
Most imsg issues come down to a permissions gate that hasn't taken effect yet, or a Messages.app behavior change on a recent macOS update. This page walks through the standard diagnoses.
Reads return unable to open database file
The terminal (or its parent process) doesn't have Full Disk Access yet.
- System Settings → Privacy & Security → Full Disk Access.
- Add the terminal you're running
imsgfrom. - Add
/System/Applications/Utilities/Terminal.appeven if you don't use it directly — macOS sometimes consults the default terminal grant. - If
imsgis launched indirectly (editor task runner, Node script, SSH session, automation gateway), grant Full Disk Access to that parent app, not just the terminal you opened. - Quit and relaunch the parent process.
If reads still fail, toggle the entry off and back on. Full Disk Access entries can go stale after Homebrew, terminal, or macOS updates. The entry looks correct but no longer carries the underlying TCC grant.
Confirm:
sqlite3 ~/Library/Messages/chat.db 'pragma quick_check;'
If sqlite3 works but imsg doesn't, the parent process of imsg is still missing the grant. If sqlite3 also fails, fix Full Disk Access first.
A supervised imsg rpc child does not need to be restarted after this fix.
Send a status request to retry the configured path; database.ready changes
to true when the open succeeds, and database methods appear in methods.
Until then those methods return -32002 (Database unavailable) while
initialize, status, direct send, eligible explicit-GUID bridge methods, and
watch.unsubscribe remain structurally available.
Reads succeed but return zero rows
Messages.app isn't signed in, or chat.db doesn't exist.
ls -la ~/Library/Messages/chat.db
If the file is missing, open Messages.app and complete iMessage / SMS Forwarding setup. The database is created lazily on first sign-in.
Sends fail with not authorized to send Apple events
Automation permission is missing.
- System Settings → Privacy & Security → Automation → Messages.
- Toggle the terminal (or wrapper app) on.
- Re-run the send.
If the toggle isn't visible, run a send once to trigger the prompt, then approve.
Sends report success but never arrive
Current versions verify every AppleScript text send against chat.db when the
database is readable. If Messages returns success but no matching outgoing row
appears within eight seconds, the CLI exits nonzero and RPC returns -32001
with may_have_completed; do not retry automatically. Direct sends made while
the database is unavailable retain the older best-effort acknowledgment.
Other routing failures to check:
Tahoe ghost-row failure. On macOS 26, Messages.app sometimes reports AppleScript success while writing an empty unjoined SMS row instead of delivering. imsg send checks explicit chat targets and existing direct chats for this row and preserves the specific ghost-row diagnostic.
Service mismatch. A send to a phone number with --service imessage fails fast if the recipient isn't on iMessage. With --service sms, Text Message Forwarding must be enabled on your iPhone for this Mac. With --service auto, imsg checks local history first; text-only direct phone sends may retry once over SMS unless --no-sms-fallback is set.
Uncertain delivery outcome. Errors marked may_have_completed or
still_in_flight are deliberately not retried or downgraded: the first
transport may already have sent the message. Check Messages/history before
taking another action. Only not_started is retry-safe.
For JSON-RPC, still_in_flight also blocks queued and future mutations with
-32004 while reads and watch control keep working. Resolve the outstanding
operation as best you can, then restart the supervised imsg rpc child to
clear the process-local mutation-lane poison. Do not repeatedly submit the
same send to the blocked child.
imsg watch goes silent after a while
macOS occasionally drops or coalesces filesystem events, especially after sleep/wake or under heavy I/O. Older versions of imsg watch could go silent in that window.
imsg 0.6.0 added a low-frequency polling fallback that runs alongside the event watcher. If the cursor falls behind, the poll catches up. imsg 0.9.1 also re-arms watches when SQLite rotates chat.db-wal or chat.db-shm. Make sure you're on 0.9.1+ (imsg --version) before debugging stale-watch reports.
If you're already on 0.9.1+ and watch still misses messages, file an issue with:
- macOS version (
sw_vers). imsg --version.- A reproduction including the exact
imsg watchflags. - The output of
ls -la ~/Library/Messages/chat.db*taken just after the silence.
react fails with unsupported reaction
imsg react only sends the six standard tapbacks Messages.app exposes reliably through automation: love, like, dislike, laugh, emphasis, question.
Custom emoji tapbacks can be read in watch --reactions output, but react rejects them rather than taking a no-op AppleScript path. There's no automation surface that sends arbitrary emoji tapbacks reliably.
imsg reports a different version than brew
Stale Homebrew install or a manually-built binary on PATH ahead of the formula:
which imsg
brew list --versions imsg
If which imsg doesn't point at the Homebrew prefix, remove the older binary or reorder your PATH.
Contacts names are missing in JSON output
The Contacts source is unavailable, the Mac has not synced the contact, or the handle has no match.
- Confirm under System Settings → Privacy & Security → Contacts that the terminal/wrapper app is enabled. Over SSH, imsg can instead use the read-only AddressBook store when the SSH service has Full Disk Access; see Contacts over SSH.
imsg nickname --local --address <handle> --jsondistinguishes unavailable access from no match withcontacts_unavailable. - Raw handles are always preserved in
sender,chat_identifier, etc. The optionalcontact_name/sender_namefields are simply omitted when no match is found.
If you want partial fallback names (initials, or formatted handles), do that in your consumer — imsg doesn't synthesize names that aren't in your Address Book.
Advanced IMCore features fail
See Advanced IMCore features. Most likely SIP is enabled (required to be off), library validation is rejecting the helper dylib, or macOS 26's imagent entitlement check is blocking the IMCore client. These are macOS-level gates imsg cannot work around.
RPC initialize, status, and bridge capability probes never launch or
restart Messages.app. Bridge-only RPC methods use only an already-running
bridge: run imsg launch outside the supervised child, then call RPC status
again. The shipped RPC typing and read methods are exceptions. Typing keeps
its bridge-first, delivery-safe direct-IMCore fallback, and read keeps IMCore
bridge activation, so either may activate Messages.app. Direct AppleScript
send may activate it too. If the ready lock is absent, bridge-only reads
return -32003; bridge-only mutations report a retry-safe not_started
delivery failure.
Filing issues
If you've worked through the relevant section above and are stuck, open an issue at https://github.com/openclaw/imsg/issues.
Useful context:
imsg --version.sw_vers(macOS version).- The exact command you ran and the full output (with any sensitive content redacted).
- Whether
sqlite3 ~/Library/Messages/chat.db 'pragma quick_check;'succeeds or fails.