Skip to content

[BUG] SQLite WAL grows unbounded (10–15 GB) while Desktop is running — disk fills to 0, recovers only on full quit #37495

Description

@vistar

Summary

opencode Desktop opens multiple independent SQLite connections to the same opencode.db (one per TUI backend + one from the Electron controller). Because each connection holds a long-lived read transaction, the WAL can never be checkpointed past the oldest reader. wal_autocheckpoint silently fails, PRAGMA wal_checkpoint(TRUNCATE) returns 1 (BUSY), and the WAL grows without bound during normal use until the disk is full. Closing the Desktop kills all connections → checkpoint finally runs → space returns.

This matches the symptom users are reporting: "opencode eats all available disk space while running, even when idle. After quitting, free space comes back."


Environment

  • opencode Desktop: v1.18.1 (Linux build, /opt/OpenCode/ai.opencode.desktop)
  • OS: Linux x86_64, ext4 on NVMe
  • Window manager: multiple windows/tabs of opencode Desktop open simultaneously
  • DB: ~/.local/share/opencode/opencode.db (SQLite in WAL mode)
  • PRAGMA wal_autocheckpoint: 1000 (default, correctly set — but ineffective, see below)

Reproduction

  1. Launch opencode Desktop.
  2. Open 2+ windows (or wait — even a single Desktop launch spawns 3 TUI backends + 1 Electron utility in my case).
  3. Use the app normally for ~30–60 min (any session activity: streaming tokens, tool calls, MCP polling).
  4. Observe opencode.db-wal growing continuously; df shows free space dropping.
  5. After hours/days of uptime with heavy MCP/plugin usage, the disk reaches 0 free.
  6. Quit opencode Desktop completely → free space returns (WAL truncates on connection close).

Observed on my machine (single Desktop launch)

$ lsof ~/.local/share/opencode/opencode.db
COMMAND        PID    NAME
opencode    1798003   ~/.local/share/opencode/opencode.db     ← TUI backend
opencode    1837890   ~/.local/share/opencode/opencode.db     ← TUI backend
opencode    1842501   ~/.local/share/opencode/opencode.db     ← TUI backend (RSS 3.3 GB)
ai.opencode.desktop 1855509  .../opencode.db                          ← Electron utility

4 concurrent connections to the same database file, each holding an open read transaction.


Root cause

SQLite's WAL mode has a fundamental constraint:

A read transaction prevents the WAL from being checkpointed past the point at which the read transaction was opened. Checkpoint can only reclaim frames older than the oldest active reader.

With N ≥ 2 always-open connections that never release their read snapshots simultaneously:

  1. Every token-stream chunk, tool output, and status update writes a new frame to the WAL (event-sourcing pattern: message.part.updated, message.updated, session.updated events dominate — I have 28,881 / 12,059 / 3,668 historical rows respectively).
  2. wal_autocheckpoint=1000 tries to fire every 1000 pages → blocked by concurrent readers → silently no-ops.
  3. WAL grows linearly with session activity.
  4. On Desktop quit: all 4 processes die, all connections drop, SQLite's shutdown hook runs wal_checkpoint(TRUNCATE) → WAL merges into main db + truncates to ~0 → space returns.

Direct evidence — checkpoint returns BUSY

$ sqlite3 ~/.local/share/opencode/opencode.db 'PRAGMA wal_checkpoint(TRUNCATE);'
1|950|930
       ↑
       1 = SQLITE_BUSY (checkpoint could not complete because of concurrent readers)

$ du -h ~/.local/share/opencode/opencode.db-wal
2,4G    ~/.local/share/opencode/opencode.db-wal   ← unchanged after the "TRUNCATE"

WAL growth observed

Time WAL size Δ
16:09 462 MB
16:30 2.4 GB +1.9 GB / 21 min

Extrapolating linearly to a multi-day session with heavy MCP usage → 10–15 GB. Matches the user-reported symptom.


Expected behavior

  • WAL should be bounded (a few hundred MB at most) thanks to wal_autocheckpoint.
  • PRAGMA wal_checkpoint(TRUNCATE) issued from any external tool should succeed and reclaim the space.
  • The Desktop should be able to run for days without filling the disk.

Actual behavior

  • WAL grows unbounded during runtime.
  • Auto-checkpoint is ineffective.
  • Manual TRUNCATE returns BUSY while the app is running.
  • Disk fills to 0; only a full Desktop quit reclaims the space.

Suggested fixes (any one of these would resolve it)

  1. Pool DB access through a single process (Desktop controller owns the only write connection; backends talk to it via IPC). This is the correct long-term fix and matches how Tauri/Electron apps typically handle SQLite.
  2. Use PRAGMA wal_checkpoint(RESTART) on a timer from the primary writer, after ensuring no long-lived read transactions are held (open read cursors with BEGIN DEFERRED and commit promptly).
  3. Switch to journal_mode=DELETE (regression in write throughput, but bounds disk usage to the main db file).
  4. At minimum, expose a "compact now" action in the Desktop UI that closes & reopens all connections, runs wal_checkpoint(TRUNCATE), and reports reclaimed space.
  5. Investigate why 3 TUI backends are spawned per Desktop launch — appears to be a separate bug (window/tab lifecycle leak).

Workarounds for affected users

  • Keep only one opencode Desktop window open. Each additional window multiplies the contention.
  • Periodically quit & relaunch Desktop after long sessions (frees the WAL).
  • External checkpoint won't work while the app is running (BUSY), so don't bother scripting it.
  • Delete stale .bak files that accumulate independently (not a runtime issue, but worth cleaning):
    ls -lah ~/.local/share/opencode/opencode.db.bak.*
    # rm after verification

Diagnostic script

Anyone wanting to verify on their machine:

echo "=== concurrent DB connections ==="
lsof ~/.local/share/opencode/opencode.db | tail -n +2 | awk '{print $1, "pid="$2}' | sort -u

echo "=== WAL size ==="
du -h ~/.local/share/opencode/opencode.db-wal

echo "=== try checkpoint (1 = BUSY = bug present) ==="
sqlite3 ~/.local/share/opencode/opencode.db 'PRAGMA wal_checkpoint(TRUNCATE);'

echo "=== autocheckpoint setting ==="
sqlite3 ~/.local/share/opencode/opencode.db 'PRAGMA wal_autocheckpoint;'

If the checkpoint returns 1|...|..., the bug is reproducing on your machine too.


Related


Priority: High — silently destroys disk capacity for any user with long sessions and plugins.

/cc @thdxr

Plugins

No response

OpenCode version

1.18.3

Steps to reproduce

  1. Launch opencode Desktop.
  2. Open 2+ windows (or wait — even a single Desktop launch spawns 3 TUI backends + 1 Electron utility in my case).
  3. Use the app normally for ~30–60 min (any session activity: streaming tokens, tool calls, MCP polling).
  4. Observe opencode.db-wal growing continuously; df shows free space dropping.
  5. After hours/days of uptime with heavy MCP/plugin usage, the disk reaches 0 free.
  6. Quit opencode Desktop completely → free space returns (WAL truncates on connection close).

Screenshot and/or share link

No response

Operating System

Manjaro Linux

Terminal

No response

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions