Skip to content

service: event seq collision drops session events after config reload #51798

Description

@ayushwardhan-iqline

Summary

Editing opencode.jsonc while a session is actively running causes the service to lose session events. Two concurrent writers allocate the same event.seq for one session aggregate, and the second insert fails on UNIQUE(aggregate_id, seq). The affected turn is reported to the model as an error and the event is dropped, leaving the session unable to continue.

Environment

  • opencode version: 2.0.18
  • OS: Linux 6.18.33.2-microsoft-standard-WSL2 feat: compact and other improvements #1 SMP PREEMPT_DYNAMIC Thu Jun 18 21:54:43 UTC 2026 x86_64 (WSL2, networkingMode=mirrored)
  • Terminal: TERM=xterm-256color, TERM_PROGRAM unset, COLORTERM unset, WT_SESSION set (Windows Terminal)
  • Shell: /usr/bin/zsh
  • Install/channel: curl install, latest channel
  • Active plugins: none configured

Reproduction

  1. Start a session and let it run a tool call so the session has in-flight event writes.
  2. While that session is still running, edit the global config at ~/.config/opencode/opencode.jsonc (even a whitespace/comment-only edit).
  3. The service watches ~/.config/opencode with inotify and reloads configuration.
  4. Within ~20 seconds, the running session's event write fails and the turn errors.

Observed twice in a single session:

2026-09-28T07:42:08.607  mtime of ~/.config/opencode/opencode.jsonc
2026-09-28T07:42:09.950  violation #1
2026-09-28T07:42:26.539  violation #2

Both failures are seq=427 on the same session aggregate, from two different event types — which is what makes this look like a sequence-allocation race rather than a duplicate insert:

params: evt_0e6f6d01b001iSAQxlXQDgakGK,ses_f191622cbffe670EoOV4COHAGu,427,message.part.updated.1
params: evt_0e6f710ea001N6MKHZveJfATKn,ses_f191622cbffe670EoOV4COHAGu,427,message.updated.1

Expected Behavior

A configuration reload should not interfere with in-flight session writes. Either the sequence allocator should serialize per aggregate so the second writer takes seq=428, or the insert should retry on conflict.

Actual Behavior

level=ERROR message=process error="Failed query: insert into \"event\" (\"id\", \"aggregate_id\", \"seq\", \"type\", \"data\") values (?, ?, ?, ?, ?)"
  cause: EffectDrizzleQueryError ... (cause: SqlError ... SQLiteError: UNIQUE constraint failed: event.aggregate_id, event.seq)

The failure propagates into Session.updateMessage -> SessionProcessor.cleanup and is surfaced to the model as an UnknownError turn. The session stopped accepting prompts afterward.

Additional Context

  • Reproduced 2 times, both within one session. I have not yet reproduced it from a clean start, so I cannot confirm the config edit is causal rather than coincidental with an unrelated write race — the reload and the collision are tightly correlated in both cases, but n=2 in a single session is weak evidence for causation.
  • The service subscribes to the config directory, so this is reachable without any explicit action beyond editing a file:
    level=INFO message="watcher subscribe" path=/home/xylar/.config/opencode type=directory ignores=3 role=server
    level=INFO message="watcher started" path=/home/xylar/.config/opencode type=directory backend=inotify ignores=3 role=server
    
  • Because sessions are event-sourced, a dropped event is not just a lost log line — it is a gap in the session's state history.
  • No workaround found other than editing config only while no session is running. Restarting the service clears the stuck state.
  • If a config edit legitimately needs to invalidate in-memory state, it would help to know whether that path is meant to be concurrency-safe.

Activity

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions