Skip to content

fix(opencode): private session DB per worker — concurrent workers were dying at "database is locked" - #79

Open
jeffhamons wants to merge 2 commits into
NateBJones-Projects:mainfrom
jeffhamons:fix/opencode-per-worker-session-db
Open

fix(opencode): private session DB per worker — concurrent workers were dying at "database is locked"#79
jeffhamons wants to merge 2 commits into
NateBJones-Projects:mainfrom
jeffhamons:fix/opencode-per-worker-session-db

Conversation

@jeffhamons

@jeffhamons jeffhamons commented Jul 27, 2026

Copy link
Copy Markdown

Fan three OpenCode workers out at once on this machine and two of them die at rc=1 before the model produces a token:

Error: Unexpected error
database is locked

OpenCode keeps its session store at $XDG_DATA_HOME/opencode/opencode.db, defaulting to ~/.local/share/opencode — one file, shared by every worker, opened for write, growing without bound. On 2026-07-27 mine stood at 1.78 GB, and the workers that lost the lock race were logged as ordinary model failures though no model had run.

The part that made this worth chasing: every non-Codex model routes through this engine, so the contention penalises exactly the cheap tier — the models you fan out widest — and it worsens as parallelism rises. It reads on the scoreboard as "the cheap lane can not cope." That is a surface misstating what happened, which is the bug class this project treats as unforgivable.

The fix

Point XDG_DATA_HOME at a per-run directory under the scratch root the wrapper already creates and tears down, so each worker gets a private store. Two details that are load-bearing:

  • Credentials live beside the DB, so the fresh root is seeded with auth.json by copying, never symlinking — the Seatbelt profile denies writes outside SCRATCH, and a symlink would resolve straight back to the shared file this exists to avoid.
  • OC_BASE ($HOME/.opencode) is added to the profile subpaths.

The --no-sandbox path deliberately keeps the shared DB and now says so in a comment: fine for a lone full-access task, not for a fan-out.

Proof

Full suite on macOS (Python 3.14), this branch rebased on current main (2c2b599): 218 of 218 pass.

tests/test_contributors.py initially failed — I have no merged work yet, so the credit audit named me. A second commit adds the README line; drop that commit if you would rather add credit at merge time.

Adjacent work

#67 adds engines/opencode-sandboxed-linux.sh. That wrapper will want the same treatment — happy to mirror it here or in a follow-up, whichever you prefer for review size.


Update: the README credit line is now a second commit on this branch, so the suite is fully green. The same line is on #79 and #80 — identical text, so whichever merges second resolves trivially. Drop the commit if you would rather handle credit yourself.

OpenCode keeps its session store at $XDG_DATA_HOME/opencode/opencode.db,
defaulting to ~/.local/share/opencode -- one file, shared by every worker,
opened for write, growing without bound. On 2026-07-27 it stood at 1.78 GB
and two of three concurrently-launched workers died before their first tool
call with "database is locked", recorded as model failures though no model
had run. Because every non-Codex model routes through this engine, the
contention penalises exactly the cheap tier, and worsens with parallelism.

Point XDG_DATA_HOME at a per-run directory under the existing scratch root so
each worker gets a private store. Credentials live beside the DB, so seed the
fresh root by COPYING auth.json -- never symlinking, since the Seatbelt
profile denies writes outside SCRATCH and a symlink would resolve straight
back to the shared file this exists to avoid.

Also add OC_BASE ($HOME/.opencode) to the profile's allowed subpaths, and note
on the --no-sandbox path that it still shares the global DB: fine for a lone
full-access task, not for a fan-out.
tests/test_contributors.py audits every author in the branch history
against `## Contributors`, so any first-time contributor's PR is red
until the line lands. Adding it here rather than leaving a red required
check for you to interpret. Identical text on both my open PRs (NateBJones-Projects#79,
NateBJones-Projects#80) so the second resolves trivially once the first merges — drop the
commit if you would rather add credit at merge time.
jeffhamons added a commit to jeffhamons/ringer that referenced this pull request Jul 27, 2026
tests/test_contributors.py audits every author in the branch history
against `## Contributors`, so any first-time contributor's PR is red
until the line lands. Adding it here rather than leaving a red required
check for you to interpret. Identical text on both my open PRs (NateBJones-Projects#79,
NateBJones-Projects#80) so the second resolves trivially once the first merges — drop the
commit if you would rather add credit at merge time.
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.

1 participant