agalwood/Motrix · critical · StaleSchemaError

new_tables_missing

new_tables_missing

Error message

The versioned database schema is incompatible with this build: expected tables `tasks`/`task_instances` are missing. This unpublished build updates the canonical v1 schema directly, so an existing local development database can have a valid version marker while its substantive tables are stale.

Action: delete the database file and restart the app to recreate it on the current v1 schema.
  rm '${dbPath}'

What it means

StaleSchemaError reason 'new_tables_missing', thrown by Guard B at line 345 when the 'tasks' OR 'task_instances' table is absent despite schema_version >= 1. A half-recovered or partially-migrated DB has a version marker but is missing the core Plan A tables; running v2+ migrations on top would fail cryptically.

Source

Thrown at src/core/session/migrations/index.ts:346

        )
        .get() !== undefined
    const hasTransferSchema =
      db
        .prepare(
          "SELECT 1 FROM sqlite_master WHERE type='table' AND name='transfer_totals'"
        )
        .get() !== undefined &&
      db
        .prepare(
          "SELECT 1 FROM sqlite_master WHERE type='table' AND name='transfer_buckets'"
        )
        .get() !== undefined
    const dbPath = (db as unknown as { name: string }).name
    if (hasLegacySchema) {
      throw new StaleSchemaError('legacy_table_present', dbPath)
    }
    if (!hasNewSchema) {
      throw new StaleSchemaError('new_tables_missing', dbPath)
    }
    const taskColumns = new Set(
      (
        db.prepare('PRAGMA table_info(tasks)').all() as Array<{ name: string }>
      ).map((column) => column.name)
    )
    if (
      !taskColumns.has('task_type') ||
      !taskColumns.has('finished_at') ||
      !taskColumns.has('error_message') ||
      !taskColumns.has('error_code') ||
      !taskColumns.has('error_detail_key') ||
      !taskColumns.has('error_detail_params') ||
      !taskColumns.has('diagnosis_revision')
    ) {
      throw new StaleSchemaError('canonical_task_columns_missing', dbPath)
    }
    if (!hasTransferSchema) {

View on GitHub (pinned to 1a708ee577)

Solutions

  1. Delete the DB and restart — migrate() recreates v1 including tasks/task_instances.
  2. If you suspect an interrupted migration, do not try to resume manually; reset and let migrate() run end-to-end.
  3. Verify the DB file is on a reliable filesystem and not being truncated by sync issues.

Example fix

# before: schema_version=1 but tasks/task_instances missing
# after
  rm '${dbPath}'
# restart; migrate() runs v1 cleanly and creates both tables
Defensive patterns

Strategy: try-catch

Type guard

function isStaleSchemaError(e: unknown): e is StaleSchemaError { return e instanceof StaleSchemaError; }

Try / catch

try {
  migrate(db);
} catch (e) {
  if (e instanceof StaleSchemaError && e.reason === 'new_tables_missing') {
    // tasks/task_instances missing — reset DB; investigate interrupted migration if recurring
  } else throw e;
}

Prevention

When it happens

Trigger: migrate() Guard B computes hasNewSchema (tasks AND task_instances both present); if false, throws at line 346. Note: this check is specifically for tasks/task_instances; task_files is checked separately at line 367 (also new_tables_missing).

Common situations: A failed/interrupted v1 migration that wrote schema_version=1 but crashed before creating tasks/task_instances; a partially-restored DB backup; manual deletion of just the tasks tables while leaving schema_version.

Related errors


AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12). Data as JSON: /api/errors/afd03c4dfb6145f0. Report an issue: GitHub.