Repository navigation
Desktop (macOS): "failed to initialize sqlite state runtime" when another Codex app-server holds logs_2.sqlite (not corruption, not size) #30105
Description
Summary
On native macOS, Codex Desktop fails to launch with the blocking dialog "Codex cannot access its local database" / failed to initialize sqlite state runtime under ~/.codex. The trigger is concurrent access: a second Codex app-server (a Codex IDE extension, an older build) was holding ~/.codex/logs_2.sqlite open, which prevented the Desktop app-server from initializing the SQLite state runtime within the startup handshake.
Both state_5.sqlite and logs_2.sqlite pass PRAGMA integrity_check (ok) and initialize fine in isolation — so this is neither corruption nor (purely) size. This is likely the same underlying cause as #27741 and #28666, but observed on native macOS and pinpointing multi-client / shared-CODEX_HOME concurrency as the trigger.
Environment
- Codex Desktop for macOS, version 26.623.30605 (build 4415)
- Bundled
codex-cli 0.142.2 - macOS 26.5.1, Apple Silicon (arm64)
- Default
~/.codexon the internal APFS volume (not WSL, no/mnt/network mount) - Several Codex clients run against the same
~/.codex(Desktop app, Codex IDE extensions, and thecodexCLI), each spawning its own ephemeralapp-server(the app-server daemon is not enabled)
User-visible failure
Codex cannot access its local database.
...
Error: (code=1, signal=null).
Most recent error: Error: failed to initialize sqlite state runtime under
~/.codex: failed to initialize state runtime at ~/.codex
Desktop logs show the handshake child exiting code=1 repeatedly, ~5–8 s per attempt:
initialize_handshake_result durationMs=7308 ... outcome=failure
reason="Error: failed to initialize sqlite state runtime under ~/.codex: failed to initialize state runtime at ~/.codex"
One internal tracing line surfaced during a failed init: WARN ... slow statement: execution time exceeded alert threshold.
Root cause (reproduced)
lsof ~/.codex/logs_2.sqliteshowed another Codexapp-server(a Codex IDE extension's, an older build) holding it (+-wal,-shm) open continuously.state_5.sqlitehad no holders.- Driving the bundled app-server directly reproduces it:
printf '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{...}}\n' | CODEX_HOME=~/.codex codex app-server→ exits1with the same error. - Bisection (all on
codex-cli 0.142.2):- Fresh empty
CODEX_HOME→ init succeeds - Fresh home + real
state_5.sqlite(170 MB) → succeeds - Fresh home + real
logs_2.sqlite(1.14 GB) → succeeds (init < 10 s) - All four real DBs together + real
config.toml→ succeeds - Real
~/.codexwhile another app-server holdslogs_2.sqlite→ fails - Kill that app-server (freeing
logs_2.sqlite), retry against real~/.codex→ succeeds (durationMs ≈ 450)
- Fresh empty
PRAGMA integrity_checkon bothstate_5.sqliteandlogs_2.sqlite=ok.
So the state DBs are healthy; the Desktop app-server simply cannot acquire the access it needs to logs_2.sqlite during init while another (often older-version) app-server holds it, and the init aborts within the startup handshake budget.
Impact
Desktop refuses to launch entirely whenever another Codex client (IDE extension / CLI / another app-server) happens to be running against the same ~/.codex. The dialog advises "Close other Codex applications," but it is not obvious that a background IDE-extension app-server counts, and the heavier "Back Up and Rebuild" is unnecessary because the DB is fine.
Workaround
Free logs_2.sqlite instead of rebuilding:
lsof ~/.codex/logs_2.sqlite # find the holding app-server PID(s)
kill <pid> # stop them
# relaunch Desktop
No data is moved or lost.
Suggestions
- Tolerate concurrent app-servers. The state runtime should coexist with other app-servers (shared WAL readers, or coordinate via the app-server daemon / single-writer with graceful waiting) instead of aborting the Desktop handshake.
- Surface the leaf cause. On macOS the error collapsed to a generic "failed to initialize state runtime at ~/.codex" with no underlying SQLite error (contrast error returnedfrom database: (code: 5) database is locked #28666, which shows
(code: 5) database is locked). Including the underlying SQLite/sqlxerror (busy / locked / pool timeout) in the dialog and logs would make this self-diagnosable. - Targeted recovery. When only
logs_2.sqliteis the blocker, offer a "retry after releasing the logs DB" / recreate-just-the-logs-DB path (cf. remote-control should recover from a corrupt logs_2.sqlite instead of failing readiness #24001) rather than the full Back Up and Rebuild.
Activity
github-actions commentedon Jun 25, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
BryanTegomoh commentedon Jun 26, 2026
Not a duplicate of #28666: that report is WSL (
\\wsl.localhost\Ubuntu-22.04\...,runCodexInWindowsSubsystemForLinux = true). This is native macOS on APFS, no WSL, default~/.codex. It does look like the same underlying bug as #27741, #28666, and #24001, so here is what narrows it.Root cause:
logs_2.sqliteis a diagnostic log store, but it sits on the critical launch path. When state-runtime init cannot get a connection from thelogs_2pool within the startup handshake, the whole app hard-fails with "Codex cannot access its local database." Two independent conditions cause that acquire failure:logs_2makes init slow (Desktop launch can fail when logs_2.sqlite grows large: app-server SQLite pool times out during startup #27741: "pool timed out while waiting for an open connection").logs_2(error returnedfrom database: (code: 5) database is locked #28666: "(code: 5) database is locked").Evidence (macOS, Desktop 26.623.30605 / codex-cli 0.142.2):
PRAGMA integrity_checkonstate_5.sqliteandlogs_2.sqliteboth returnok, so this is not corruption.lsof ~/.codex/logs_2.sqliteshowed a second (older-build) Codex app-server holding it; Desktop init then failedcode=1after ~7s on every attempt.logs_2initializes fine for a single client in isolation, so the trigger is contention, not the file.Workaround without data loss (better than "Back Up and Rebuild"):
Suggested fix: take
logs_2off the critical launch path. It is diagnostics, so its init should be lazy and non-fatal, degrading logging instead of blocking launch (aligns with #24001). If it must init at startup, setbusy_timeoutand raise the pool-acquire budget. Also surface the leaf error: on macOS the dialog collapses to a generic message with no cause, unlike #28666 and #27741.Happy to send a full
RUST_LOGtrace or test a patch.Nicolas0315 commentedon Jun 26, 2026
I pushed a candidate fix here:
https://github.com/openai/codex/compare/main...Nicolas0315:codex/logs-db-nonfatal-fallback?expand=1
What changed:
StateRuntimenow treatslogs_2.sqlitelock/busy failures as non-fatal during startup.codex.sqlite.fallback.countand uses a single-connection in-memory logs DB for the current process, so existing log insert/query APIs still work.Local validation on
08aaf33d1:just fmtgit diff --checkcargo test --manifest-path codex-rs\Cargo.toml -p codex-state init_uses_ephemeral_logs_db_when_disk_logs_db_is_locked -- --nocapturecargo test --manifest-path codex-rs\Cargo.toml -p codex-tui embedded_state_db_corruption_preserves_failed_database_for_cli_recovery -- --nocapturecargo test --manifest-path codex-rs\Cargo.toml -p codex-state -- --nocapturecargo check --manifest-path codex-rs\Cargo.toml -p codex-state -p codex-tui -p codex-app-serverSSH validation:
cyberagent-mac-m5max: fetched08aaf33d1;git diff --check HEAD~1 HEADOK; focused lock regression OK; cargo check OK.nicolas2025: fetched08aaf33d1; diff check OK; focused lock regression OK; cargo check OK; no lingering cargo/rustc/link processes afterward.nicolas-macbook-pro: fetched08aaf33d1; diff check OK; no cargo installed, so diff-only.rtx5060ti: fetched08aaf33d1; diff check OK; cargo is blocked by the host's existinglink.exetoolchain issue (link: extra operand ..., exit 101); no lingering cargo processes afterward.boombx403-byte commentedon Aug 18, 2026
Hi @BryanTegomoh, cross-platform WSL/Windows path mismatches often make healthy transcripts look broken when workspace contexts change. Codex Rescue Alpha5 explicitly separates transcript integrity from workspace path-family portability without rewriting saved paths.
If you'd like to check the local rollout safely:
Please sanitize private paths before posting any output.
BryanTegomoh commentedon Aug 23, 2026
Update: I can no longer reproduce this on Desktop 26.818.41509 with bundled codex-cli 0.149.0-alpha.4.1. Two app-server processes are currently sharing
~/.codex/logs_2.sqlite, including one started while the other was already running.#33938 added consistent WAL settings and a five-second busy timeout after this report, which appears to have mitigated the observed case. Current main still aborts startup if logs DB initialization ultimately fails, so the non-fatal fallback remains unresolved.
@anp-oai, was #33938 intended to resolve this case? If so, I am fine closing this unless it recurs.
1328837476-hug commentedon Aug 27, 2026
Root-cause analysis + one-line fix suggestion for the un-actionable
failed to initialize sqlite state runtimeerror (cross-posting this analysis here because it applies to every sqlite state-runtime init failure report, including #30105, #39015, #32160; hit it while debugging the Windows desktop startup chain in #40752)While debugging a machine where the desktop app failed to start, the app-server surfaced:
Neither layer names the failing database or the underlying sqlite error, even though the code already has all of it:
codex-rs/state/src/runtime/recovery.rsdefinesRuntimeDbInitError { label, operation, path, source }with Displayfailed to {operation} {label} at {path}: {source}— exactly the information neededcodex-rs/rollout/src/state_db.rswraps it with.with_context("failed to initialize state runtime at {home}")— chain preservedcodex-rs/app-server/src/lib.rs(both sqlite-init failure paths, ~line 609 and ~1254) formats withformat!("... {err}")— and the plain anyhow Display prints only the outermost context, silently dropping theRuntimeDbInitErrorlayer below itSo users see the two generic outer layers and none of the specifics (which DB of the six, open vs migrate, which path, which sqlite error code). On the machine I debugged, the actual failure was a schema-level
state_5.sqliteincompatibility —integrity_check: ok, all_sqlx_migrationsrowssuccess=1— and pinning it down required manually bisecting all six*.sqlitefiles out of~/.codex.Suggested fix (two characters per site)
(also the sibling site in
init_sqlite_state_db_with_fresh_start_on_corruption). The{err:#}alternate form appends the fullCaused by:chain — the same patternrollout/src/state_db.rsalready uses inemit_startup_warning(&format!("failed to initialize state runtime: {err:#}")). With it, the same failure becomes immediately diagnosable:A regression test could assert that
format!("{err:#}")for an init failure on a garbage state DB contains"failed to open state DB"and the DB path (the existingruntime_db_path_for_corruption_error_returns_failed_database_pathtest incodex-rs/state/src/runtime/recovery_tests.rsalready shows how to construct that failure).Happy to provide the full patch if useful — per
docs/contributing.mdI'm keeping it as an issue analysis rather than a PR.fix(codex): retry shared-state conflict before blocking stdio spawn