anomalyco / anomalyco/opencode

Daily "Failed to execute statement" on macOS with concurrent opencode processes (1.18.30, busy_timeout=0, 21 GB DB)

Open
#48,416 2 comments 0 reactions 1 assignee View on GitHub

@rekram1-node is already working on this.

Since Sep 11, 2026.

Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

Description

Local opencode CLI/Desktop sessions intermittently fail with Failed to execute statement (and the UI surfaces it as error: UnknownError). On my machine this happens "every day now", most often right after a bash tool subprocess returns — which is exactly the moment opencode writes the tool-result part back into the SQLite session store.

Reproduction setup (just one machine, no virtualization):

  • macOS 15.5 arm64
  • opencode 1.18.30
  • single user account, default data directory ~/.local/share/opencode/
  • several opencode processes run against the same opencode.db: a long-lived TUI/Desktop session from a few days ago, a couple of overnight opencode run workers, and the foreground session I am trying to use
  • PRAGMA busy_timeout on the live DB returns 0, journal_mode=wal, integrity_check=ok

What the user actually sees:

  1. The agent's response for that turn finishes with finish: tool-calls, error: { name: "UnknownError", data: { message: "Failed to execute statement" } }.
  2. The corresponding tool part inside that message already has state.status = "completed" with the real stdout — so the tool result is not lost, only the wrapper message write to SQLite failed.
  3. The next prompt in the same session usually goes through; the failure is non-deterministic and not tied to a particular tool or prompt.

OpenCode log excerpt (timestamp preserved from the same day):

timestamp=2026-09-11T01:58:23.969Z level=ERROR run=a2a9e52e message=process \
  session.id=ses_f71dab2b7ffe2qdxk7y9xkt85d messageID=msg_08e2e9604001lLC96eHJdN3tR8 \
  error="Failed to execute statement" stack="Error
    at <anonymous> (/$bunfs/root/chunk-szxn2m7h.js:54:29098)
    at runLoop (/$bunfs/root/chunk-awr5yyef.js:25:2045)
    at evaluate (/$bunfs/root/chunk-awr5yyef.js:25:1435)
    at <anonymous> (/$bunfs/root/chunk-awr5yyef.js:25:5664)
    at <anonymous> (/$bunfs/root/chunk-awr5yyef.js:25:22490)
    at evaluate (/$bunfs/root/chunk-awr5yyef.js:25:1691)
    at <anonymous> (/$bunfs/root/chunk-awr5yyef.js:25:5664)
    at Y7 (/$bunfs/root/chunk-awr5yyef.js:25:39080)
    at <anonymous> (/$bunfs/root/chunk-szxn2m7h.js:80:23438)
    at emit (node:events:98:22)
    at #maybeClose (node:child_process:766:16)
    at #handleOnExit (node:child_process:520:72)
    at processTicksAndRejections (native:7:39)"

Key thing in this stack: the failure is being raised inside the node:child_process handleOnExit handler that fires right after the bash subprocess closes. So the write that loses the race is the post-tool message/part write triggered by handleOnExit, not the tool's own call site.

I see the same stack pattern 4 times in a 17-minute window, all under the same DB. Four concurrent opencode processes have that DB open (lsof ~/.local/share/opencode/opencode.db):

opencode. 38499 ... 13u ... /Users/jelvin/.local/share/opencode/opencode.db   # running ~2d16h
opencode. 87705 ... 13u ... /Users/jelvin/.local/share/opencode/opencode.db   # running ~1d16h
opencode. 96583 ... 13u ... /Users/jelvin/.local/share/opencode/opencode.db   # running ~1d18h
opencode. 82411 ... 13u ... /Users/jelvin/.local/share/opencode/opencode.db   # ~17 min
opencode. 80097 ... 12u ... /Users/jelvin/.local/share/opencode/opencode.db   # foreground session, ~17 min

DB facts:

  • ~/.local/share/opencode/opencode.db is 21 GB with a 700 KB WAL
  • busy_timeout = 0, journal_mode = wal, integrity_check = ok
  • disk free: 407 GB on the data volume, so SQLITE_FULL is not the cause

The wrapped Drizzle/Kysely SQL error is being flattened to the string "Failed to execute statement" before it reaches the session error envelope (per #36578). Because the SQLite cause is dropped, I cannot tell from the session log whether each occurrence is SQLITE_BUSY, SQLITE_LOCKED, or SQLITE_BUSY_SNAPSHOT. Given that busy_timeout=0, multiple writers, and the failure points to writes triggered right after a child process exit, SQLITE_BUSY is the most likely root cause.

Expected behavior

A failure to grab the SQLite write lock should not kill the surrounding prompt. The user-visible behavior should be one of:

  • transparently retry the statement (with backoff) so the prompt completes
  • surface the underlying SQLite cause (SQLITE_BUSY: database is locked or similar) instead of "Failed to execute statement"
  • if the write truly cannot make progress, retry long enough to give the other process a chance to release the lock instead of immediately failing the message
Steps to reproduce
  1. Run opencode 1.18.30 on macOS arm64.
  2. Have several opencode processes (TUI, Desktop, opencode run worker, etc.) open the same ~/.local/share/opencode/opencode.db concurrently.
  3. Let at least one of them stay alive for hours/days while issuing prompts.
  4. Issue prompts that involve the bash tool — the failure shows up almost immediately after a bash subprocess returns and opencode tries to persist the tool result / message.
  5. Inspect the session's message and part rows; the tool part row is already written and state.status = completed, but the surrounding message row carries error.name = "UnknownError", error.data.message = "Failed to execute statement".
Mitigation tried / observed locally

Killing the long-lived opencode processes (the two that had been running 1–2 days) makes the failure stop, until the next time one of them runs long enough to coexist with a new writer. The DB is healthy (integrity_check = ok); the failure is contention, not corruption.

OpenCode version

1.18.30

Operating System

macOS 15.5 (24F74), Darwin 24.5.0 arm64 (MacBook Pro 16, M-series)

Additional context

This looks like the same root cause as #47566, #38849, #33320, and #21215 — busy_timeout = 0 in the bun-sqlite / node-sqlite connection, combined with concurrent opencode processes, and Effect.orDie on the SQL adapter turning lock timeouts into fatal message failures. The two companion PRs that would actually fix it are already open:

  • #47567 — retry SQLite statements on lock timeout in both bun and node drivers
  • #44558 — serialize database init and migrations across processes

Reporting this separately because the symptom on the user side (a single failing assistant message with a successful tool part already written) is consistent enough across several local days to be worth a dedicated reproduction, and the WAL file growth + 21 GB main DB on a single-user laptop suggests the contention window is also creating the WAL grows unbounded pattern from #37495.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.