-
-
Notifications
You must be signed in to change notification settings - Fork 69.3k
SQLITE_CANTOPEN should be classified as transient, not fatal (kills LaunchAgent) #34678
Description
Problem
SQLITE_CANTOPEN errors cause the gateway process to exit when running as a LaunchAgent on macOS. The same error is survived in terminal mode because it's caught by local try/catch handlers, but when it escapes to the global unhandledRejection handler, it falls through to process.exit(1) because it's not in any safe-list.
This creates a crash loop under launchd: crash → restart → crash → throttle → silent death.
Root Cause
In src/infra/unhandled-rejections.ts (compiled to audio-transcription-runner-*.js), the error classification has:
FATAL_ERROR_CODES→ exit(1)CONFIG_ERROR_CODES→ exit(1)TRANSIENT_NETWORK_CODES→ log and continue- Everything else → exit(1)
SQLite transient errors (SQLITE_CANTOPEN, SQLITE_BUSY, SQLITE_LOCKED, SQLITE_IOERR) are not in any safe-list. They fall through to the catch-all process.exit(1).
Proposed Fix
Add a TRANSIENT_SQLITE_CODES set (or add to the existing transient set):
const TRANSIENT_SQLITE_CODES = new Set([
"SQLITE_CANTOPEN",
"SQLITE_BUSY",
"SQLITE_LOCKED",
"SQLITE_IOERR"
]);And check it in installUnhandledRejectionHandler alongside isTransientNetworkError.
Environment
- OpenClaw v2026.3.2
- macOS (arm64), Node v25.6.1
- LaunchAgent plist with correct TMPDIR, HOME, PATH, WorkingDirectory
- QMD auto-update disabled (interval: 0)
- Related: LaunchAgent plist missing TMPDIR causes SQLITE_CANTOPEN on macOS #20489 (TMPDIR fix doesn't apply here), Unhandled fetch rejection crashes gateway, launchd throttles after crash loop #14649 (same crash-loop pattern)
Workaround
Manually patching the compiled dist files to add SQLite codes to TRANSIENT_NETWORK_CODES. This survives until the next openclaw update.