thedotmack/claude-mem · critical

schema v46: missing .

Error message

schema v46: missing ${target.table}.${target.column}

What it means

During the schema-v46 migration (ensureSyncRevisionTextAffinity, run from the SessionStore constructor), PRAGMA table_info does not list the expected sync-revision column on the target table. This is an internal invariant: the migration assumes the column exists, and its absence means the schema is in an unexpected state, so startup aborts.

Solutions

  1. Restore a database backup taken before the failed migration
  2. Check which schema_versions rows exist and run the migration chain from a matching app version
  3. Recreate the database by deleting ~/.claude-mem/claude-mem.db if data is disposable
  4. Report the DB state (PRAGMA table_info output) as a bug if the column should exist
Defensive patterns

Strategy: try-catch

Validate before calling

// check target column exists before opening the store
const cols = db.query("PRAGMA table_info(sdk_sessions)").all();
if (!cols.some(c => c.name === 'sync_rev')) console.error('DB missing sync_rev; restore backup');

Try / catch

try { store = new SessionStore(dbPath); } catch (e) {
  if (String(e.message).startsWith('schema v46: missing')) {
    restoreBackupOrRebuild(dbPath); // fatal: cannot continue with this DB
  } else throw e;
}

Prevention

When it happens

Trigger: Opening a database whose schema is older/newer than expected such that sync_rev (or the other v46 target column) is missing from the target table when the v46 affinity migration runs.

Common situations: Restoring a partially migrated database file from backup; downgrading the app after a future schema version dropped the column; a corrupted or hand-edited database.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17). Data as JSON: /api/errors/6af7a3c441fe46d6. Report an issue: GitHub.

Appendix: source

Thrown at src/services/sqlite/SessionStore.ts:707

    const columnInfo = (table: string, column: string): TableColumnInfo | undefined =>
      (this.db.query(`PRAGMA table_info(${table})`).all() as TableColumnInfo[])
        .find(info => info.name === column);
    const isText = (info: TableColumnInfo | undefined): boolean =>
      info?.type.trim().toUpperCase() === 'TEXT';
    const applied = this.db.prepare(
      'SELECT version FROM schema_versions WHERE version = ?'
    ).get(46) as SchemaVersion | undefined;

    if (applied && targets.every(target => isText(columnInfo(target.table, target.column)))) {
      return;
    }

    const tx = this.db.transaction(() => {
      for (const target of targets) {
        const columns = this.db.query(`PRAGMA table_info(${target.table})`).all() as TableColumnInfo[];
        const source = columns.find(info => info.name === target.column);
        if (!source) {
          throw new Error(`schema v46: missing ${target.table}.${target.column}`);
        }

        for (const raw of streamRows(this.db.query(`
          SELECT CAST(id AS TEXT) AS row_id,
                 typeof(${target.column}) AS storage_type,
                 CAST(${target.column} AS TEXT) AS revision
          FROM ${target.table}
        `))) {
          const row = raw as { row_id: string; storage_type: string; revision: string | null };
          if (row.storage_type === 'real') {
            throw new Error(
              `schema v46: ${target.table}.${target.column} row ${row.row_id} is REAL and unrecoverably rounded`
            );
          }
          if (row.storage_type !== 'integer' && row.storage_type !== 'text') {
            throw new Error(
              `schema v46: ${target.table}.${target.column} row ${row.row_id} has unsupported ${row.storage_type} storage`
            );

View on GitHub (pinned to d8bc9755e7)