Background service resumes sessions still running on another server that shares the database #51213
Description
Activity
Thanks for the detailed report and #51215. I confirmed overlapping executions on a local 2.0.15-based build sharing its DB between an unregistered server and the managed service; each failed request preceded the other server’s tool completion. I am carrying both commits from #51215 (46 execution tests pass). There is also a separate deterministic lowering problem: an update followed by an available or repaired error result still throws. Repro in #51764; fixing that does not replace the live-owner recovery guard.
Hit this from T3 Code (2.0.22; restart.ts is unchanged in 2.0.24). The second server was started by an agent: in a thread served by T3's own
opencode serve --hostname 127.0.0.1 --port N, the model ranopencode mcp listto debug an MCP login, and the CLI auto-startedopencode serve --service. Its boot sweep resumed both sessions T3's server was running ("The server restarted while you were working" 0.15 s after start), and for 3h22m the two servers alternated steps. Each had a different MCP set, so one session got 437 full Code Mode catalog notices (~4 MB stored) and was auto-compacted.Repro on 2.0.24 (VM): T3 thread runs
sleep 120; date >> runs.txt→opencode mcp listin a shell → the service marks the running shell call "Tool execution interrupted" whilesleepkeeps running, the resumed model starts the same command again (twosleepprocesses, two lines in runs.txt, twoidlerows for one turn).Workaround until #51215 lands:
{"disabled": true}in~/.config/opencode/service.json. CLI commands then use a standaloneserve --stdio, which never sweeps; same repro: onesleep, one line, no notice. Onlyopencode service start/restart,pairandserve --servicestill start the managed service.Also on 2.0.24 (macOS arm64): two managed services with separate XDG state/config but a shared
opencode.db. Service B's boot log showsFailed to drain Sessionfor two sessions still running in A.Another effect: the resumed turn runs with B's tools, cwd and sandbox. A turn started in a sandboxed server can continue in an unsandboxed one.
Source:
restart.ts:192-231only checks the localexecution.active. Fix: record the claim owner (server id + heartbeat) and skip claims whose owner is alive.
Description
When a second OpenCode server shares the data directory, the managed service's startup recovery resumes sessions that the other server is still running. It marks their in-flight tool calls as aborted, adds "The server restarted while you were working", and starts its own step, so two servers drive one session.
Execution claims only store a timestamp, so the sweep can't tell a dead owner from a live one.
restart.tsassumes "unregistered servers sharing the database never sweep", but their live claims still get swept by the service.What I saw: a desktop client runs its own bundled
opencode serve --port <n>, and the background service started while that server was mid-turn. When the original server's subagents finished, its next request failed with:because the history now had the service's unresolved tool calls in it. The session stayed stuck until I sent another message. I didn't hit this on V1.
Plugins
None (isolated repro)
OpenCode version
2.0.16 (also seen with a 2.0.15 client-bundled server next to a 2.0.16 service)
Steps to reproduce
XDG_CONFIG_HOME/XDG_DATA_HOME/XDG_STATE_HOME/XDG_CACHE_HOMEdirs and an Anthropic model.opencode serve --port 4801.sleep 150 && echo done."opencode serve --service --port 4799.Screenshot and/or share link
No response
Operating System
macOS 26 (Darwin 25.3.0, arm64)
Terminal
N/A (API-driven repro)