thedotmack/claude-mem · critical
schema v46: . row is REAL and unrecoverably rounded
Error message
schema v46: ${target.table}.${target.column} row ${row.row_id} is REAL and unrecoverably rounded What it means
The v46 migration converts sync-revision columns to TEXT affinity. A row whose value is stored as SQLite REAL has already lost precision (uint64 revisions cannot round-trip through a float), so the migration refuses to proceed rather than copying a corrupted revision.
Solutions
- Identify the row: SELECT CAST(id AS TEXT), typeof(sync_rev) FROM <table> WHERE typeof(sync_rev)='real'
- Restore a pre-migration database backup
- Manually repair the row's revision to its correct integer-as-text value if known, then retry
- Report as a bug; the value is unrecoverable from the DB alone
Example fix
-- repair a REAL-stored revision to canonical text UPDATE sdk_sessions SET sync_rev = '42' WHERE id = 7 AND typeof(sync_rev) = 'real';
Defensive patterns
Strategy: try-catch
Validate before calling
const bad = db.query("SELECT COUNT(*) c FROM sdk_sessions WHERE typeof(sync_rev)='real'").get();
if (bad.c > 0) console.error(`${bad.c} REAL-stored revisions need repair before upgrade`); Try / catch
try { store = new SessionStore(dbPath); } catch (e) {
if (String(e.message).includes('unrecoverably rounded')) {
restoreBackup(dbPath); // revision data is already corrupted
} else throw e;
} Prevention
- Bind uint64 revisions as strings/BigInt in any external writer, never as JS numbers
- Avoid manual UPDATEs against revision columns
- Take a pre-migration DB backup
When it happens
Trigger: A row in the target table whose typeof(column) === 'real' is encountered while streaming rows during ensureSyncRevisionTextAffinity.
Common situations: A previous bug or external tool (e.g. writing the revision with a driver that binds JS numbers) stored the revision as a float; manual UPDATE statements that set the revision to a decimal literal.
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
- Column not found in , skipping rename
- schema v46: failed to copy
- schema v46: missing .
- schema v46: . row has unsupported storage
- schema v46: . row is not a positive canonical uint64…
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/b83edffb164119c7.
Report an issue: GitHub.
Appendix: source
Thrown at src/services/sqlite/SessionStore.ts:718
}
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`
);
}
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;View on GitHub (pinned to d8bc9755e7)