Skip to content

fix: switch SQLite from WAL to DELETE journal mode to prevent corruption#14326

Open
theabecaster wants to merge 2 commits intoanomalyco:devfrom
theabecaster:fix/sqlite-journal-mode-docker-corruption
Open

fix: switch SQLite from WAL to DELETE journal mode to prevent corruption#14326
theabecaster wants to merge 2 commits intoanomalyco:devfrom
theabecaster:fix/sqlite-journal-mode-docker-corruption

Conversation

@theabecaster
Copy link

@theabecaster theabecaster commented Feb 19, 2026

Issue for this PR

Closes #14194

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

SQLite WAL mode uses a shared memory file (-shm) via mmap to coordinate across processes. Docker bind mounts on macOS don't reliably propagate mmap or fcntl locks, so two instances sharing ~/.local/share/opencode/ silently corrupt the database.

This switches journal_mode from WAL to DELETE (eliminating the -shm file entirely), replaces wal_checkpoint(PASSIVE) with locking_mode = EXCLUSIVE (so the second instance gets SQLITE_BUSY instead of SQLITE_CORRUPT), and updates json-migration.ts which was re-setting journal mode to WAL during bulk inserts.

No performance impact — opencode uses one connection per process, so WAL's concurrent-read advantage was unused.

How did you verify your code works?

  • Ran bun dev locally with the pragma changes, sessions create and update normally
  • Typecheck passes across all packages
  • With two instances on the same DB, the second gets a clear SQLITE_BUSY error after busy_timeout (5s) instead of SQLITE_CORRUPT

Screenshots / recordings

Not a UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

WAL mode relies on shared memory (mmap) and POSIX file locking via the
-shm file, both of which are unreliable across Docker volume mounts on
macOS. When two instances share the same database through bind mounts,
the broken mmap coordination causes silent data corruption
(SQLITE_CORRUPT).

Switch to DELETE journal mode which eliminates the -shm shared memory
dependency entirely. Add EXCLUSIVE locking mode so the process holds
the database lock for its connection lifetime — a second instance gets
a clear SQLITE_BUSY error instead of silent corruption.

Performance impact is negligible since opencode uses a single connection
per process, making WAL's concurrent-read advantage unused.

Closes anomalyco#14194
@github-actions github-actions bot added needs:compliance This means the issue will auto-close after 2 hours. and removed needs:compliance This means the issue will auto-close after 2 hours. labels Feb 19, 2026
@github-actions
Copy link
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

@dejwi
Copy link

dejwi commented Feb 21, 2026

please fix, multiple opencode instances nuke all of my sessions;d

@github-actions github-actions bot mentioned this pull request Feb 21, 2026
6 tasks
@d4rky-pl
Copy link

d4rky-pl commented Mar 2, 2026

Looks like the specs are failing on this PR:

SQLiteError: database is locked
      errno: 5,
 byteOffset: -1,
       code: "SQLITE_BUSY"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Running opencode locally and in docker while sharing config corrupts the database

3 participants