Skip to content

core: V1 migration fails against older previous-channel database schemas #43139

Closed

Description

@opencode-agent

Summary

The V1→V2 migration fails with SQLiteError: near ",": syntax error when opencode-next.db was created by an older previous-channel build whose project or session table lacks nullable columns expected by the current importer.

The importer reads source rows with SELECT * into current TypeScript shapes. Missing properties become undefined; raw SQL interpolation emits an empty expression such as VALUES (..., , ...), and the per-session transaction rolls back. Migration remains incomplete and retries on the next server process.

This broadens #41341: fork_boundary is one affected field, but the compatibility defect applies to every assumed source column added after the source database was created.

Environment

  • opencode version: 0.0.0-beta-17519
  • OS: macOS arm64; exact Darwin version unavailable from diagnostics
  • Terminal: Not applicable; observed through packaged Desktop
  • Shell: Unavailable; diagnostics only report that a login shell environment loaded
  • Install/channel: Beta
  • Previous-channel database version: service last registered as 0.0.0-next-16416
  • Active plugins: Unavailable from exported diagnostics

Reproduction

  1. Create or retain an opencode-next.db from an older V2 build such as next-16416.
  2. Ensure it contains at least one project and session, and that its schema predates one or more nullable columns expected by the current importer.
  3. Start a current V2 server so V1Migration.layer runs.
  4. Observe that normal schema migrations complete.
  5. Observe the background data migration fail with:
    V1 migration failed
    SQLiteError: near ",": syntax error
    
  6. Start another server process and observe the incomplete migration retry.

Expected Behavior

The migration should tolerate all supported historical previous-channel schemas:

  • Existing columns should be copied.
  • Absent nullable columns should be projected as SQL NULL.
  • Absent required columns should produce a direct compatibility error naming the table and column.
  • Source values must always be bound safely; undefined must never become an empty SQL expression.
  • Successfully committed sessions should remain idempotent across retries.

Actual Behavior

The importer declares current row shapes containing fields such as:

project:
  icon_url_override
  icon_color
  commands

session:
  fork_boundary
  time_suspended

It then reads the old database without adapting its schema:

source.query<NextProject, []>("SELECT * FROM project").all()
source.query<NextSession, []>("SELECT * FROM session ORDER BY id DESC").all()

For a column absent from the source table, property access returns undefined. The destination SQL interpolates those values directly:

sql`
  INSERT INTO session_v2 (..., fork_session_id, fork_boundary, slug, ...)
  VALUES (..., ${session.fork_session_id}, ${session.fork_boundary}, ${session.slug}, ...)
`

The generated statement can contain:

VALUES (..., value, , value, ...)

SQLite rejects it with:

SQLiteError: near ",": syntax error

The transaction rolls back, including its migration cursor update, so the same input fails again on a later server process.

Additional Context

Observed timeline

All timestamps UTC:

23:16:52.519  new server process starts
23:16:52.750  normal database migrations begin
23:16:52.771  normal database migrations complete
23:16:54.798  V1 migration fails: SQLiteError near ","

The diagnostic window contains one server run and one V1 migration attempt. Client relaunches reused the same server. This rules out concurrent or duplicate migration execution as the cause of this occurrence.

The event cleanup is also not the malformed statement. It uses fixed SQL:

DELETE FROM event
WHERE rowid IN (SELECT rowid FROM event LIMIT ?)

The near-comma failure occurs later, while importing rows from the previous-channel database.

Static call stack and data flow

CLI / Desktop client
  Service.ensure(currentVersion)
    starts `opencode-cli serve --service`

ServerProcess.start
  createRoutes
    Database layer
      DatabaseMigration.apply
        normal schema migrations succeed
    V1Migration.layer
      forks V1Migration.run
        read durable `migration.v1-v2` state
        count/read `<global-data>/opencode-next.db`
        importNextDatabase
          SELECT * FROM project
          SELECT * FROM session
          source row lacks historical column
          property read returns undefined
          tx.run(INSERT INTO project/session_v2)
          SQL template emits empty value between commas
          SQLite parser throws
          transaction rolls back
      catches cause
      runtime migration status = error

Inputs and outputs

Input:
  current destination database
  older opencode-next.db
  source table schema
  source project/session rows

Transformation:
  SELECT * into current TypeScript interface
  property access for columns not guaranteed by source schema
  SQL-template interpolation

Output:
  malformed INSERT statement
  SQLite syntax error
  rolled-back session import
  incomplete migration state

TUI and Desktop behavior

Neither UI initiates this migration directly. The server auto-starts it through V1Migration.layer. The TUI migration overlay only polls status. Clients may replace a registered service when versions differ, but the observed failure occurs inside one server process and one migration run.

Related issue

Suggested fix

  1. Inspect each source table with PRAGMA table_info.
  2. Build an explicit source projection for the supported current shape.
  3. Select NULL AS <column> for absent nullable fields.
  4. Fail early with a named compatibility error for absent required fields.
  5. Use bound destination inserts that preserve null and reject undefined before SQL generation.
  6. Add fixtures for multiple historical project and session schemas, not only the fork_boundary variant.

Activity

  1. changed the title [-]desktop: failed V1 migration makes restored sessions fatal after beta upgrade[/-] [+]core: V1 migration fails against older previous-channel database schemas[/+] on Aug 17, 2026
  2. argszero commented on Aug 18, 2026

    @argszero
    Contributor

    Just noting for anyone hitting this on the beta channel: this is already fixed by #43142 (fix(core): support older previous-channel databases, merged into v2 on 2026-08-18).

    The importer now inspects the source schema via pragma_table_info and builds an explicit projection: existing columns are selected normally, absent optional columns are projected as SQL NULL, and absent required columns fail early with a compatibility error naming the table and columns. undefined can no longer become an empty SQL expression, so the near ",": syntax error is gone. Regression coverage was added in packages/core/test/v1-migration.test.ts.

    Since the merge base was v2 (not the default branch), GitHub did not auto-close this issue — likely safe to close once verified on a beta build.

  3. Tarquinen commented on Oct 20, 2026

    @Tarquinen
    Contributor

    This was fixed by #43142. That PR merged into the v2 branch, so GitHub didn't close this issue automatically. Closing as completed.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

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