{"record":{"id":"b83edffb164119c7","repo":"thedotmack/claude-mem","slug":"schema-v46-target-table-target-column-row","errorCode":null,"errorMessage":"schema v46: ${target.table}.${target.column} row ${row.row_id} is REAL and unrecoverably rounded","messagePattern":"schema v46: (.+?)\\.(.+?) row (.+?) is REAL and unrecoverably rounded","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/services/sqlite/SessionStore.ts","lineNumber":718,"sourceCode":"    }\n\n    const tx = this.db.transaction(() => {\n      for (const target of targets) {\n        const columns = this.db.query(`PRAGMA table_info(${target.table})`).all() as TableColumnInfo[];\n        const source = columns.find(info => info.name === target.column);\n        if (!source) {\n          throw new Error(`schema v46: missing ${target.table}.${target.column}`);\n        }\n\n        for (const raw of streamRows(this.db.query(`\n          SELECT CAST(id AS TEXT) AS row_id,\n                 typeof(${target.column}) AS storage_type,\n                 CAST(${target.column} AS TEXT) AS revision\n          FROM ${target.table}\n        `))) {\n          const row = raw as { row_id: string; storage_type: string; revision: string | null };\n          if (row.storage_type === 'real') {\n            throw new Error(\n              `schema v46: ${target.table}.${target.column} row ${row.row_id} is REAL and unrecoverably rounded`\n            );\n          }\n          if (row.storage_type !== 'integer' && row.storage_type !== 'text') {\n            throw new Error(\n              `schema v46: ${target.table}.${target.column} row ${row.row_id} has unsupported ${row.storage_type} storage`\n            );\n          }\n          try {\n            assertCanonicalDecimal(row.revision, { positive: true });\n          } catch {\n            throw new Error(\n              `schema v46: ${target.table}.${target.column} row ${row.row_id} is not a positive canonical uint64 revision`\n            );\n          }\n        }\n\n        if (isText(source)) continue;","sourceCodeStart":700,"sourceCodeEnd":736,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/services/sqlite/SessionStore.ts#L700-L736","documentation":"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.","triggerScenarios":"A row in the target table whose typeof(column) === 'real' is encountered while streaming rows during ensureSyncRevisionTextAffinity.","commonSituations":"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.","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"],"exampleFix":"-- repair a REAL-stored revision to canonical text\nUPDATE sdk_sessions SET sync_rev = '42' WHERE id = 7 AND typeof(sync_rev) = 'real';","handlingStrategy":"try-catch","validationCode":"const bad = db.query(\"SELECT COUNT(*) c FROM sdk_sessions WHERE typeof(sync_rev)='real'\").get();\nif (bad.c > 0) console.error(`${bad.c} REAL-stored revisions need repair before upgrade`);","typeGuard":null,"tryCatchPattern":"try { store = new SessionStore(dbPath); } catch (e) {\n  if (String(e.message).includes('unrecoverably rounded')) {\n    restoreBackup(dbPath); // revision data is already corrupted\n  } else throw e;\n}","preventionTips":["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"],"tags":["schema","migration","sqlite","data-corruption"],"backgroundTag":"schema-validation-failed","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}