You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Bug: stale event sequence permanently rejects new session events #51411
A durable aggregate can become permanently unwritable when event_sequence.seq falls behind rows already present in event. The next local publish derives seq = event_sequence.seq + 1, updates the sequence row, then collides with the existing (aggregate_id, seq) unique index. The transaction rolls back, so every later prompt repeats the same collision.
The event log itself remains intact; the failure is the stale sequence cursor. New publishes should recover inside the existing immediate transaction by deriving the local high-water mark from both tables, then write the next contiguous sequence without changing owner-claim behavior.
Plugin developers commonly run and compare v1 and v2 while supporting both host generations. That is a normal development workflow, not an unsupported user mistake. If only OPENCODE_CONFIG_DIR is isolated while the default data DB remains shared, cross-generation startup can leave an active v1 session damaged (see #42260). This defensive recovery is necessary for a legacy database already left in that state; it does not replace proper v1/v2 data isolation.
Plugins
None
OpenCode version
1.18.32 (observed); latest dev inspected for the fix
Steps to reproduce
Create an aggregate and durable events through any normal OpenCode path.
In a stopped, disposable SQLite fixture, lower only that aggregate's event_sequence.seq below the highest event.seq; do not alter the event rows.
Start OpenCode and publish another durable event for the aggregate.
Observe UNIQUE constraint failed: event.aggregate_id, event.seq; retries use the same stale sequence and the session remains unusable.
This can be left behind by historical cross-version/shared-database migration scenarios. Related context: #42260, #42444, #42389, and the template-closed report #51316.
This issue might be a duplicate of existing issues. Please check:
#51316: reports the same UNIQUE constraint failed: event.aggregate_id, event.seq error and a permanently unusable session after retries. It attributes the collision to concurrent sequence assignment, while this issue describes a stale event_sequence cursor.
Thanks for the duplicate check. #51316 and this report share the visible failure (UNIQUE constraint failed: event.aggregate_id, event.seq) and the permanent retry behavior, but they do not establish the same initial cause. #51316 attributes the first collision to concurrent assignment. This report deterministically isolates a durable post-condition: an aggregate already has an event head higher than its persisted event_sequence cursor. A later publish derives an already-used sequence; rollback leaves that cursor unchanged, so every retry collides again.\n\nThat durable mismatch could plausibly be left behind after a concurrent collision, but it can also be introduced by historical shared-database/cross-version scenarios. PR #51413 reconciles the cursor with the actual event head in the same transaction before allocating the next sequence. It does not replace correct concurrent allocation, but it makes either persisted stale-cursor state recoverable.\n\nI will defer to maintainers on whether #51411 should be treated as a duplicate, related report, or the recovery-focused follow-up to #51316.
Hit this in the wild without any manual fixture edits — the desync developed during normal streaming.
Evidence from the live DB (binary v2.0.22, Linux x64, WAL mode, 9.6G shared opencode.db):
One session: 687 contiguous events (seq 42–728), but event_sequence.seq stuck at 691. Next publish tried seq 692 → UNIQUE constraint failed: event.aggregate_id, event.seq → whole drain aborted (prompt_async failed), session permanently unwritable; every retry collides on the same seq.
Only 1 of 1089 aggregates in event_sequence was affected.
Reverse direction also observed: after the crash, a failed retry drain advanced event_sequence 728 → 1118 with zero new events committed (max stayed 728). So the counter is decoupled from committed events in both directions, not just behind.
Workaround used: manual UPDATE event_sequence SET seq=(SELECT max(seq)...). This supports the in-transaction high-water-mark recovery suggested in the issue description — deriving the next seq from both tables would have self-healed both directions here.
I couldn't reproduce this on v2 (@opencode/cli@2.2.0, the latest release). Here's what I did:
Sent a prompt in a new session. event_sequence.seq for the session was 6.
Lowered only that cursor by 2, leaving everything else alone.
Sent two more prompts. Both went through with no UNIQUE constraint failed: event.aggregate_id, event.seq error, and the cursor carried on from 4.
On v2 a stale cursor can't cause this collision. The local CLI and service never write rows to the event table: the write is behind a persist option that defaults to off in packages/core/src/bus.ts, and only the workerd server turns it on. So there is nothing for event_sequence.seq + 1 to collide with. The same logic is in v2.0.32, v2.1.0 and current dev (86ce19d).
The failure you describe comes from v1 (opencode-ai 1.x, including 1.18.32), which does write event rows. The v2 reports of the same error came from a v1 or desktop 1.x process sharing one opencode.db with v2, as in #42260. Current v2 keeps its data in a separate opencode-next.db. v1 only receives fixes for critical bugs, so a recovery step there is unlikely.
If you can trigger this on v2 alone, with no v1 or desktop 1.x process using the same data directory, please reply with your opencode --version, the database path in use and the steps. We'll look again.
We haven't heard back, so I'm closing this as not planned.
To recap: I couldn't reproduce this on v2 (@opencode/cli@2.2.0). After I lowered a session's event_sequence.seq, the next prompts still went through, because the local v2 app doesn't write rows to the event table. The collision you describe comes from v1 (1.18.32) writing to a database shared with v2. v1 only receives fixes for critical bugs, and current v2 keeps its data in a separate opencode-next.db. Related: #56460, #54464, #52395, #42260.
If this happens on v2 alone, with no v1 or desktop 1.x process using the same data directory, please open a new issue with your opencode --version, the database path and the steps, and we'll look again. Thanks for the detailed report.
Activity
github-actions commentedon Sep 25, 2026
This issue might be a duplicate of existing issues. Please check:
UNIQUE constraint failed: event.aggregate_id, event.seqerror and a permanently unusable session after retries. It attributes the collision to concurrent sequence assignment, while this issue describes a staleevent_sequencecursor.d4n-sec commentedon Sep 25, 2026
Thanks for the duplicate check. #51316 and this report share the visible failure (
UNIQUE constraint failed: event.aggregate_id, event.seq) and the permanent retry behavior, but they do not establish the same initial cause. #51316 attributes the first collision to concurrent assignment. This report deterministically isolates a durable post-condition: an aggregate already has an event head higher than its persistedevent_sequencecursor. A later publish derives an already-used sequence; rollback leaves that cursor unchanged, so every retry collides again.\n\nThat durable mismatch could plausibly be left behind after a concurrent collision, but it can also be introduced by historical shared-database/cross-version scenarios. PR #51413 reconciles the cursor with the actual event head in the same transaction before allocating the next sequence. It does not replace correct concurrent allocation, but it makes either persisted stale-cursor state recoverable.\n\nI will defer to maintainers on whether #51411 should be treated as a duplicate, related report, or the recovery-focused follow-up to #51316.ImBIOS commentedon Oct 4, 2026
Hit this in the wild without any manual fixture edits — the desync developed during normal streaming.
Evidence from the live DB (binary v2.0.22, Linux x64, WAL mode, 9.6G shared opencode.db):
event_sequence.seqstuck at 691. Next publish tried seq 692 →UNIQUE constraint failed: event.aggregate_id, event.seq→ whole drain aborted (prompt_async failed), session permanently unwritable; every retry collides on the same seq.event_sequencewas affected.event_sequence728 → 1118 with zero new events committed (max stayed 728). So the counter is decoupled from committed events in both directions, not just behind.opencode serveon 127.0.0.1, the second spawned right after the crash, plus a pre-existingopencode serve --service). Possibly related to session: two server processes sharing one opencode.db allocate session_message.seq independently - UNIQUE(seq) collisions fail sessions #53146.Workaround used: manual
UPDATE event_sequence SET seq=(SELECT max(seq)...). This supports the in-transaction high-water-mark recovery suggested in the issue description — deriving the next seq from both tables would have self-healed both directions here.opencodejr commentedon Oct 28, 2026
Thanks for the precise report and steps.
I couldn't reproduce this on v2 (
@opencode/cli@2.2.0, the latest release). Here's what I did:event_sequence.seqfor the session was 6.UNIQUE constraint failed: event.aggregate_id, event.seqerror, and the cursor carried on from 4.On v2 a stale cursor can't cause this collision. The local CLI and service never write rows to the
eventtable: the write is behind apersistoption that defaults to off inpackages/core/src/bus.ts, and only the workerd server turns it on. So there is nothing forevent_sequence.seq + 1to collide with. The same logic is in v2.0.32, v2.1.0 and currentdev(86ce19d).The failure you describe comes from v1 (
opencode-ai1.x, including 1.18.32), which does write event rows. The v2 reports of the same error came from a v1 or desktop 1.x process sharing oneopencode.dbwith v2, as in #42260. Current v2 keeps its data in a separateopencode-next.db. v1 only receives fixes for critical bugs, so a recovery step there is unlikely.Related issues:
If you can trigger this on v2 alone, with no v1 or desktop 1.x process using the same data directory, please reply with your
opencode --version, the database path in use and the steps. We'll look again.opencodejr commentedon Oct 31, 2026
We haven't heard back, so I'm closing this as not planned.
To recap: I couldn't reproduce this on v2 (
@opencode/cli@2.2.0). After I lowered a session'sevent_sequence.seq, the next prompts still went through, because the local v2 app doesn't write rows to theeventtable. The collision you describe comes from v1 (1.18.32) writing to a database shared with v2. v1 only receives fixes for critical bugs, and current v2 keeps its data in a separateopencode-next.db. Related: #56460, #54464, #52395, #42260.If this happens on v2 alone, with no v1 or desktop 1.x process using the same data directory, please open a new issue with your
opencode --version, the database path and the steps, and we'll look again. Thanks for the detailed report.