Skip to content

[v2] Silent part persistence failure — message/part rows never written after sidecar startup #51020

Open

Description

@famewolf

Summary

After the desktop sidecar process takes over (v2.0.12+), no message or part rows are written to opencode.db — ever. session_v2 rows still update, and model requests are still made to the LLM backend (confirmed via llama-swap access logs), but nothing persists. Sessions appear to be "working" indefinitely with zero visible token output.

Reproduction

  1. Run opencode desktop app (any 2.x version, sidecar ≥ 2.0.12)
  2. Start a new session or continue an existing one
  3. Send a prompt
  4. Observe: session shows "working", model request fires (visible in backend logs), but no tokens appear in UI
  5. Check DB: SELECT COUNT(*) FROM part WHERE created_at > '...' → zero new rows since sidecar startup

Evidence

From a live installation (opencode-desktop 1.18.31, sidecar auto-updated 2.0.12 → 2.0.15):

-- Last message row written:
SELECT MAX(created_at) FROM message;
-- 2026-09-22 18:39:40  (the exact minute the 2.0.12 sidecar started)

-- Last part row written:
SELECT MAX(created_at) FROM part;
-- 2026-09-22 18:40:04

-- Parts on 09-23 (next day, across ALL sessions including a fresh one):
SELECT COUNT(*) FROM part WHERE date(created_at) = '2026-09-23';
-- 0

-- But session_v2 rows DO update:
SELECT MAX(updated_at) FROM session_v2;
-- 2026-09-23 20:22:38 (fresh session, still "working")

Backend confirmed model requests succeeded (llama-swap access log):

  • 200 OK with 1.65MB response body at ~20:30 (7m38s duration)
  • 200 OK with 1.63MB response body at ~20:35 (4m9s duration)
  • 200 OK with 586KB response body at ~20:40 (8m15s duration)
  • Plus multiple 499 client aborts at ~5-6min (opencode client timeout)

Schema context

The v2 migration (20260923013825_project_time_active) introduced the new session_v2/message/part schema where part.message_id is NOT NULL (FK to message). No foreign key violations or errors appear in the log — the write simply never happens.

Impact

  • All sessions are wedged: they show "working" forever, no tokens visible
  • User cannot see any model output in the UI
  • The model IS being called (tokens are generated server-side) but the results are never persisted
  • Affects all sessions simultaneously (old + new)
  • No workaround found

Environment

  • opencode desktop: 1.18.31 (AUR opencode-desktop-bin)
  • Sidecar: 2.0.12 (initial) → 2.0.15 (auto-updated)
  • OS: Arch Linux
  • DB: ~/.local/share/opencode/opencode.db (1.03GB, 165 sessions, 19112 message rows, 69755 part rows — all pre-2026-09-22 18:40)
  • Model: local llama-server via llama-swap (OpenAI-compatible API at http://192.168.2.215:11436/v1)

Log

No errors in ~/.local/share/opencode/log/opencode.log. The sidecar process runs serve --service and appears healthy.

Workaround

Downgrade to v1 desktop (1.18.x) — but this requires a fresh database since v1 cannot read the v2-migrated schema. All session history is inaccessible (data is intact in the v2 DB, just unreadable by v1).

Activity

  1. Dante-dan commented on Oct 8, 2026

    @Dante-dan
    Contributor

    I compared this report with the current v2 source at 0621ea9. The current projector persists updates through SessionMessageUpdater into session_message, whose schema is defined here. That differs from the session_v2 / message / part tables described in this report. The migration named 20260923013825_project_time_active adds project activity tracking; this source check does not reproduce the reported desktop sidecar behavior or establish its root cause.

    Could you share the exact sidecar version/build that exhibits this, and whether its database has advancing durable event rows while the UI stays in “working”? A sanitized schema listing for the affected database (sqlite_master table names and the relevant columns for the message/event tables) would also help identify which persistence path and version to trace. Please omit local paths, credentials, and tokens.

  2. famewolf commented on Oct 8, 2026

    @famewolf
    Author

    Data from the affected installation, as requested.

    1. Versions

    • opencode-desktop: 1.18.31-1 (AUR opencode-desktop-bin, Arch Linux)
    • Sidecar exhibiting the failure: 2.0.12 as installed, auto-updated to 2.0.15 during the incident (report filed 2026-09-24)
    • Sidecar running today: serve --service on v2.0.18 (uptime > 2 days), plus a second serve --hostname 127.0.0.1 --port 43513 instance

    2. Do durable event rows advance while the UI stays "working"?

    No. On the affected database nothing advances at all:

    table rows last activity (UTC)
    event 514 created = 0 for every row — column never populated, no new rows
    message 806 2026-09-27 03:58
    part 2,876 2026-09-27 03:58
    session_message 837 2026-09-24 23:47
    session_v2 (max time_updated) 14 2026-09-24 23:47

    Notes:

    • This database was recreated fresh on 2026-09-24 01:34 UTC (an hour before the report was filed) — the original 1.03 GB / 19,112-message database quoted in the report is no longer present. The replacement shows the same full silence after its last write; session_v2 kept advancing for about a day after message/part activity stopped, then froze too.
    • The failure mode is therefore total silence rather than partial progress: no event rows, no session_v2 updates, no FK violations, no errors in the log — the write simply never happens, matching the report.

    3. Sanitized schema listing

    Affected database — 24 tables:
    account, account_state, control_account, credential, event, event_sequence, instruction_blob, instruction_entry, instruction_state, kv, message, migration, part, permission, project, project_directory, session, session_inbox, session_message, session_pending, session_share, session_v2, todo, workspace, worktree

    CREATE TABLE message (
      id text PRIMARY KEY,
      session_id text NOT NULL,
      time_created integer NOT NULL,
      time_updated integer NOT NULL,
      data text NOT NULL,
      FOREIGN KEY (session_id) REFERENCES session(id) ON DELETE CASCADE
    );
    CREATE TABLE part (
      id text PRIMARY KEY,
      message_id text NOT NULL,
      session_id text NOT NULL,
      time_created integer NOT NULL,
      time_updated integer NOT NULL,
      data text NOT NULL,
      FOREIGN KEY (message_id) REFERENCES message(id) ON DELETE CASCADE
    );
    CREATE TABLE event (
      id text PRIMARY KEY,
      aggregate_id text NOT NULL,
      seq integer NOT NULL,
      type text NOT NULL,
      data text NOT NULL,
      created integer DEFAULT 0 NOT NULL,
      FOREIGN KEY (aggregate_id) REFERENCES event_sequence(aggregate_id) ON DELETE CASCADE
    );

    All timestamps are unixepoch milliseconds.

    One more finding relevant to your source check

    The current v2 runtime writes to its own data directory, whose database has no message/part tables at all — its schema is session_v2 + session_message + event only. On sidecar 2.0.18 that path is healthy: session_message has 17,965 rows, session_v2 has 140, and the WAL file is being rewritten continuously while sessions are active (checked 2026-10-08; last write within the same minute as the check). That database's event table has 0 rows.

    So the observed timeline is consistent with your reading of 0621ea9: the message/part schema from this report stopped receiving writes after 2026-09-27, and current versions persist through session_message via SessionMessageUpdater. On 2.0.18 the session persistence behaves normally — no reproduction of the reported silence on that path.

  3. Dante-dan commented on Oct 8, 2026

    @Dante-dan
    Contributor

    Thanks, this separates the inactive database from the healthy v2.0.18 persistence path.

    One additional source detail: the V1 migration runner returns immediately once its migration state is completed; completion is recorded here. This is a one-time import into the V2 model, not ongoing writes back to the legacy message/part tables. Their last-write timestamps alone therefore cannot diagnose a current V2 persistence failure. The CLI database selection also depends on OPENCODE_DB, the data root, and the release channel, so two databases need not be the same active runtime store.

    Your current session_message/WAL activity is consistent with the current writer. It does not establish what caused the original 2.0.12–2.0.15 UI stall or whether the historical sessions imported successfully. Those remain separate questions; the missing original database and the absence of a failure on the current active path prevent assigning a persistence root cause from these counts. I have not reproduced the historical desktop failure or verified its migration outcome.

  4. famewolf commented on Oct 9, 2026

    @famewolf
    Author

    Fair points, all four taken:

    1. Agreed — the V1 migration runner is a one-time import, so the legacy message/part last-write timestamps cannot diagnose a current V2 persistence failure. Dropping that leg.
    2. Also agreed the active store needs pinning: CLI database selection depends on OPENCODE_DB, the data root, and the release channel. Next data from this side: the active-store identification from the affected setup, so both sides look at the same database.
    3. Current session_message/WAL activity being consistent with the current writer is noted — that covers the healthy path, not the historical one.
    4. The open questions stand: what caused the original 2.0.12–2.0.15 UI stall, and whether the historical sessions imported successfully. The original database is unavailable, so a persistence root cause cannot be assigned from counts — understood.

    Net of it: no reproducible root cause on the current path, and the historical failure cannot be recreated from what is available. Any new information from this setup gets reported back here.

  5. opencodejr commented on Oct 28, 2026

    @opencodejr
    Contributor

    Thanks for the detailed report! Before we can reproduce this, a few things need checking.

    About the database evidence: in v2, conversation content is no longer written to the v1 message/part tables. It goes to session_message (alongside session_v2). So seeing no new rows in message/part after the migration is expected and doesn't by itself mean anything is failing. Could you check whether new rows appear there instead, e.g.:

    SELECT COUNT(*), MAX(time_created) FROM session_message;

    A possible cause: by default v2 waits 300 seconds for a provider to start responding (headerTimeout). Your llama-swap logs show requests taking 4–8 minutes and 499 aborts at about 5–6 minutes, which fits a local server that takes longer than that on a large prompt. If you can, try raising headerTimeout (in milliseconds) in your provider's settings, or try a small prompt in a fresh session, and see whether output appears.

    It would also help to have, in your own words and briefly:

    • The exact output of opencode --version for the sidecar and the desktop app version you're running now
    • What you did, what you expected, and what you see in the UI (a screenshot helps)
    • Whether the same happens with a hosted model or a small/fast local model
    • The lines in ~/.local/share/opencode/log/ from the time a session was stuck, even if they aren't errors

    You can reply here with the details, or edit the issue. If you edit it, please also leave a comment saying you've updated it so we know you're done.

  6. famewolf commented on Oct 29, 2026

    @famewolf
    Author

    Replying to the bot's 2026-10-28T06:31:37Z evidence request. Box: opencode v2.2.0 (sidecar/server). No separate desktop client on this host; the client is the web UI over the sidecar, so both resolve to v2.2.0 here.

    Live DB (v2 schema, 20 tables): session_message has 58601 rows; newest time_created = 1793206035903 (≈ 2026-10-28, today). session_v2 has 372 rows. There is no separate part/p1 table in this schema — parts are embedded in the message row (so a "part persistence failure" would have to be inside the message-row write path, not a missing table).

    headerTimeout: live config (opencode.jsonc lines 276-277) sets both timeout and headerTimeout to 3600000 ms (1 hour). The 300 s default is already overridden on this box, so the 499 s stall is not explained by the default timeout alone.

    Repro: none on this box at check time. The 09-24 incident window is gone from the log directory (only opencode.log remains, 1611 lines, oldest entry 2026-10-26T21:21Z), so the original stuck-period lines are unavailable. If it recurs, the log around the stall is the next useful data point.

    Small hosted-model test: not run this pass (would need a fresh session plus a hosted model; the symptom is intermittent and not reproducible here). A controlled data point is available on request.

    graphicsMode=direct: 237 rows in the T9 table (from the earlier probe).

    If any of the above numbers look off (e.g. the MAX timestamp conversion), the raw value 1793206035903 is the canonical one.

  7. opencodejr commented on Oct 31, 2026

    @opencodejr
    Contributor

    We're closing this for now because we haven't heard back. We needed a few details before we could reproduce it.

    To recap: in v2, conversation content goes to session_message, not the v1 message/part tables, so the database evidence in the report doesn't by itself show a persistence failure. The 499 aborts at about 5–6 minutes may be v2's default 300-second headerTimeout with a slow local server, and raising it may help.

    If sessions still get stuck, please open a new issue with the output of opencode --version, whether new session_message rows appear, what you see in the UI, and the log lines from the time it happened, and we'll take another look. Thanks!

  8. famewolf commented on Oct 31, 2026

    @famewolf
    Author

    Your bot needs to learn how to read. I replied 2 days ago.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions