thedotmack/claude-mem · error · Error
canonical content: exceeds the local SQLite safe-integer…
Error message
canonical content: ${name} exceeds the local SQLite safe-integer range What it means
canonicalDecimalToSafeInteger converts a canonical decimal value (e.g. a server timestamp) into a JS number for storage in SQLite. Because SQLite/JS only guarantee safe integers up to 2^53-1, it throws when Number(canonical) is not a safe integer, preventing silent precision loss.
Solutions
- Convert the source timestamp unit (e.g. divide nanoseconds by 1e6) so the value fits in the safe-integer range before syncing.
- Check the server/system clock configuration for wildly wrong epoch values.
- If larger values are legitimate, persist them as strings instead of routing through canonicalDecimalToSafeInteger.
Example fix
// before const ts = canonicalDecimalToSafeInteger(serverNanos, 'serverTs'); // after const ts = canonicalDecimalToSafeInteger(BigInt(serverNanos) / 1000000n, 'serverTs'); // nanos -> millis
Defensive patterns
Strategy: type-guard
Validate before calling
const n = Number(value);
if (!Number.isSafeInteger(n)) {
throw new Error(`${name} out of safe-integer range; convert units first`);
} Type guard
function isSafeInt(v: unknown): v is number {
return typeof v === 'number' && Number.isSafeInteger(v);
} Try / catch
try {
ts = canonicalDecimalToSafeInteger(rawServerTs, 'serverTs');
} catch (e) {
if (e.message.includes('safe-integer')) { ts = normalizeTimestampUnit(rawServerTs); }
else throw e;
} Prevention
- Normalize timestamp units (nanos/micros -> millis) before sync.
- Validate server clock configuration; absurd epochs signal misconfiguration.
- Store oversized numerics as strings rather than forcing them into SQLite integers.
When it happens
Trigger: Calling canonicalDecimalToSafeInteger (or its callers serverTs / localPayload) with a decimal whose numeric value is outside Number.MIN_SAFE_INTEGER..Number.MAX_SAFE_INTEGER, e.g. a microsecond/nanosecond-precision timestamp or a server clock producing values > 9007199254740991.
Common situations: A server emitting timestamps in nanoseconds or microseconds while the client expects milliseconds; a remote clock misconfigured to epoch-far-future values; importing records from a system using larger numeric ids/timestamps.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- cloud sync canonical payload
- cloud sync canonical payload
- cloud sync canonical payload
- cloud sync canonical payload
- Column not found in , skipping rename
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/83d1704153a240db.
Report an issue: GitHub.
Appendix: source
Thrown at src/services/sync/CanonicalContent.ts:138
export function compareCanonicalDecimals(left: string, right: string): -1 | 0 | 1 {
assertCanonicalDecimal(left);
assertCanonicalDecimal(right);
if (left.length !== right.length) return left.length < right.length ? -1 : 1;
if (left === right) return 0;
return left < right ? -1 : 1;
}
export function incrementCanonicalDecimal(value: string): string {
const canonical = assertCanonicalDecimal(value);
if (BigInt(canonical) === UINT64_MAX) jsonError('uint64 sequence overflow');
return (BigInt(canonical) + 1n).toString(10);
}
export function canonicalDecimalToSafeInteger(value: unknown, name: string): number {
const canonical = assertCanonicalDecimal(value);
const parsed = Number(canonical);
if (!Number.isSafeInteger(parsed)) {
throw new Error(`canonical content: ${name} exceeds the local SQLite safe-integer range`);
}
return parsed;
}
export function stableDocumentId(
kind: ContentKind,
originDeviceId: string,
originLocalId: string,
): string {
if (!CONTENT_KINDS.has(kind)) jsonError(`unsupported content kind ${String(kind)}`);
const deviceId = assertDeviceId(originDeviceId);
const localId = assertCanonicalDecimal(originLocalId);
const input = canonicalJson([
'cmem-doc-id-v1',
'device',
kind,
deviceId,
localId,View on GitHub (pinned to d8bc9755e7)