Skip to content

server: V1 migration fails with SQLiteError near ',' on apostrophes in legacy message data #41869

Closed

Description

@mellena1

Summary

The V1 → V2 data migration ("V1 migration") fails on every server startup with SQLiteError: near ",": syntax error when the legacy databases contain single quotes (apostrophes) in message/part JSON payloads. The migration interpolates JSON values directly into SQL statements without escaping, so any apostrophe in a message breaks the string literal and the parser dies at the next comma.

Environment

  • opencode version: 0.0.0-next-17229 (also reproduced on 0.0.0-next-17227)
  • OS: Linux 7.1.7-arch1-1 (x64)
  • Terminal: ghostty (TERM=xterm-ghostty)
  • Shell: zsh
  • Install/channel: next
  • Active plugins: @mellena1/opencode-auto-mode@0.1.2

Reproduction

  1. Have a V1 install with message/part data containing apostrophes (e.g. tool output or user prompts with '), plus a previous V2 (opencode-next.db) database whose session_message.data contains apostrophes.
  2. Run opencode2 (server startup runs the V1 migration against opencode.db in place).
  3. Migration fails every startup; the migration.v1-v2 kv entry stays at {"phase":"sessions"} and never advances.

Log (every startup):

level=ERROR message="V1 migration failed" cause="Cause([Die(SQLiteError: near \",\": syntax error)])" role=server

Relevant data found in the legacy databases:

  • old V2 db session_message: 72 of 109 rows contain ' in data
  • V1 message: 768 of 8757 rows contain ' in data
  • V1 part: 8805 of 40252 rows contain ' in data

Expected Behavior

The V1 migration should import legacy sessions/messages regardless of content, e.g. by using parameterized statements or escaping string literals (' → '').

Actual Behavior

The migration builds INSERT statements via raw SQL string interpolation. From the installed bundle, the copy-from-previous-V2-db step runs:

INSERT INTO session_message (id, session_id, type, seq, time_created, time_updated, data)
VALUES (... ${k.data} ...)

and the session conversion step runs:

INSERT INTO session_message (id, session_id, type, seq, time_created, time_updated, data)
VALUES (... ${JSON.stringify(L.data)} ...)

Both interpolate unescaped JSON. An apostrophe in the payload terminates the string literal early and SQLite reports near ",": syntax error at the following comma. The transaction rolls back (including the phase cursor write), so the migration retries and fails on every startup.

Additional Context

  • Updating from 0.0.0-next-17227 to 0.0.0-next-17229 did not fix it.
  • Removing the old V2 db would not fix it either: the V1 message/part data itself contains apostrophes and would hit the same path.
  • Workaround used to unblock: set the kv entry migration.v1-v2 to {"phase":"completed"} in opencode.db (skips the migration; legacy data remains untouched in the db). This is not a fix — the import is skipped entirely and the phase is sticky, so a fixed build should reset/clear this key when re-running.
  • Server log lines before the failure: schema migrations 20260804233008_loose_psylocke, 20260805200742_import_legacy_credentials, 20260808023530_workspace_domain, 20260811161259_execution_claim_attempts all complete; only the V1 data migration fails.

Activity

  1. github-actions commented on Aug 11, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of (or related to) existing issues. Please check:

    • V1→V2 session migration fails when previous channel DB lacks fork_boundary #41341: V1→V2 session migration fails with the same SQLiteError: near ",": syntax error and the same stuck {"phase":"sessions"} state. The root cause there is undefined values producing empty SQL expressions in the same string-interpolated INSERT statements — the same underlying pattern as the apostrophe escaping problem described here. Both are symptoms of the same raw SQL interpolation approach in the V1 migration code.
  2. opencode-agent commented on Aug 12, 2026

    @opencode-agent
    Contributor

    Fixed by #41877, which now writes migrated session messages through the typed Drizzle insert builder with JSON payloads bound as SQL parameters. Regression coverage includes apostrophes in both legacy V1 data and previous-V2 message data.

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions