thedotmack/claude-mem · critical

schema v46: . row has unsupported storage

Error message

schema v46: ${target.table}.${target.column} row ${row.row_id} has unsupported ${row.storage_type} storage

What it means

During the v46 revision-affinity migration, a row's sync-revision column has a SQLite storage type other than integer or text (e.g. 'real' is handled separately, so this catches blob/null-adjacent or other odd storage). The migration only knows how to normalize integer and text values, so it fails fast.

Solutions

  1. Find the offending row with: SELECT CAST(id AS TEXT), typeof(sync_rev) FROM <table> WHERE typeof(sync_rev) NOT IN ('integer','text','real')
  2. Fix or delete the malformed row, then restart
  3. Restore a pre-migration backup
  4. Report as a bug with the row's storage type

Example fix

-- inspect and repair a BLOB-stored revision
UPDATE sdk_sessions SET sync_rev = CAST(sync_rev AS TEXT) WHERE typeof(sync_rev) = 'blob';
Defensive patterns

Strategy: try-catch

Validate before calling

const bad = db.query("SELECT COUNT(*) c FROM sdk_sessions WHERE typeof(sync_rev) NOT IN ('integer','text','real')").get();
if (bad.c > 0) console.error('BLOB/other storage in revision column; repair before upgrade');

Try / catch

try { store = new SessionStore(dbPath); } catch (e) {
  if (String(e.message).includes('unsupported') && String(e.message).startsWith('schema v46')) {
    repairOrRestore(dbPath);
  } else throw e;
}

Prevention

When it happens

Trigger: Streaming rows in ensureSyncRevisionTextAffinity encounters typeof(column) not in ('integer','text','real') — e.g. a BLOB-stored revision.

Common situations: External tooling or a different driver inserted a BLOB into the revision column; database corruption from a crashed non-SQLite writer.

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/06564fb64f5a4ded. Report an issue: GitHub.

Appendix: source

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

        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`
            );
          }
          try {
            assertCanonicalDecimal(row.revision, { positive: true });
          } catch {
            throw new Error(
              `schema v46: ${target.table}.${target.column} row ${row.row_id} is not a positive canonical uint64 revision`
            );
          }
        }

        if (isText(source)) continue;
        if (columns.some(info => info.name === target.temporary)) {
          throw new Error(`schema v46: unexpected temporary column ${target.table}.${target.temporary}`);
        }

        this.db.run(

View on GitHub (pinned to d8bc9755e7)