thedotmack/claude-mem · critical
schema v48: invalid v47 applied_at
Error message
schema v48: invalid v47 applied_at ${applied.applied_at} What it means
When initializing the sync hub launch baseline (schema v48), the migration derives a time boundary from the v47 migration's recorded applied_at timestamp. If that stored timestamp cannot be parsed to a safe, non-negative epoch ms, the recorded migration metadata is corrupt and startup aborts rather than computing a wrong exclusion boundary.
Solutions
- Inspect: SELECT applied_at FROM schema_versions WHERE version = 47 and fix it to a valid ISO 8601 UTC timestamp
- Restore a backup of the database from before v47/v48
- Rebuild the database if historical sync-exclusion boundaries are not needed
- Report as a bug if applied_at was never hand-modified
Example fix
-- before applied_at = 'yesterday' -- after UPDATE schema_versions SET applied_at = '2026-09-17T12:00:00.000Z' WHERE version = 47;
Defensive patterns
Strategy: try-catch
Validate before calling
const v47 = db.prepare('SELECT applied_at FROM schema_versions WHERE version = 47').get();
const ok = v47 && Number.isSafeInteger(Date.parse(v47.applied_at)) && Date.parse(v47.applied_at) >= 0;
if (v47 && !ok) console.error('Corrupt v47 applied_at:', v47.applied_at); Try / catch
try { store = new SessionStore(dbPath); } catch (e) {
if (String(e.message).startsWith('schema v48: invalid v47 applied_at')) {
restoreBackupOrRepairTimestamp(dbPath);
} else throw e;
} Prevention
- Never hand-edit schema_versions rows
- Verify timestamps are ISO 8601 when copying DB data between environments
- Back up the DB before version upgrades
When it happens
Trigger: initializeSyncRevisionBaseline runs on a DB where schema_versions has v47 recorded but its applied_at is empty, malformed (non-ISO), negative, or not a safe integer when parsed with Date.parse.
Common situations: Hand-edited or partially restored schema_versions table; a clock/serialization bug when v47 was originally applied; copying rows between DBs with wrong timestamp formats.
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 is REAL and unrecoverably rounded
- schema v46: . row has unsupported storage
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/381543be7471de59.
Report an issue: GitHub.
Appendix: source
Thrown at src/services/sqlite/SessionStore.ts:909
this.db.prepare('INSERT INTO schema_versions (version, applied_at) VALUES (?, ?)').run(47, appliedAt);
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(48, appliedAt);
});
tx();
return;
}
// Repair databases that ran the earlier v47 implementation before the
// explicit exclusion ledger existed. v47 stamped the launch baseline at
// its applied_at millisecond. Rows still stamped at/before that boundary
// are the excluded launch revisions; NULL or later stamps are post-launch
// writes/acks and must remain eligible for an epoch rebuild.
const exclusionsApplied = this.db.prepare(
'SELECT version FROM schema_versions WHERE version = ?'
).get(48) as SchemaVersion | undefined;
if (exclusionsApplied && exclusionTableExisted) return;
const boundaryMs = Date.parse(applied.applied_at);
if (!Number.isSafeInteger(boundaryMs) || boundaryMs < 0) {
throw new Error(`schema v48: invalid v47 applied_at ${applied.applied_at}`);
}
const repair = this.db.transaction(() => {
for (const { table, kind } of tables) {
this.db.prepare(`
INSERT OR IGNORE INTO sync_launch_exclusions (kind, origin_local_id, through_rev)
SELECT ?, CAST(id AS TEXT), CAST(sync_rev AS TEXT)
FROM ${table}
WHERE origin_device_id IS NULL
AND synced_at > 0
AND synced_at <= ?
`).run(kind, boundaryMs);
}
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)')
.run(48, new Date().toISOString());
});
repair();
}
View on GitHub (pinned to d8bc9755e7)