{"record":{"id":"c2d0654b3b729f59","repo":"agalwood/Motrix","slug":"label-exceeds-the-javascript-safe-integer-range-c2d065","errorCode":null,"errorMessage":"${label} exceeds the JavaScript safe integer range","messagePattern":"(.+?) exceeds the JavaScript safe integer range","errorType":"validation","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"src/core/lib/sqlite-integers.ts","lineNumber":9,"sourceCode":"/**\n * Conversions between better-sqlite3 `safeIntegers()` rows and JavaScript\n * numbers, shared by the SQLite-backed stores.\n */\n\nexport function safeIntegerFromSql(value: unknown, label: string): number {\n  if (typeof value === 'number') {\n    if (!Number.isSafeInteger(value)) {\n      throw new RangeError(`${label} exceeds the JavaScript safe integer range`)\n    }\n    return value\n  }\n  if (typeof value !== 'bigint') {\n    throw new RangeError(`${label} is not an integer`)\n  }\n  if (\n    value < BigInt(Number.MIN_SAFE_INTEGER) ||\n    value > BigInt(Number.MAX_SAFE_INTEGER)\n  ) {\n    throw new RangeError(`${label} exceeds the JavaScript safe integer range`)\n  }\n  return Number(value)\n}\n\nexport function nonNegativeIntegerFromBigInt(\n  value: bigint,\n  label: string","sourceCodeStart":1,"sourceCodeEnd":27,"githubUrl":"https://github.com/agalwood/Motrix/blob/1a708ee57746c434e2c67a44bbf0906a976afea4/src/core/lib/sqlite-integers.ts#L1-L27","documentation":"`safeIntegerFromSql` converts a value read from a better-sqlite3 row (under `safeIntegers()` mode, where big ints arrive as `bigint`) into a JavaScript `number`. It throws this `RangeError` when a stored `INTEGER` column holds a value outside `+/-2^53-1` — a SQLite integer too large to represent precisely as a JS number. The `label` identifies the column or field for diagnostics.","triggerScenarios":"Reading a SQLite column whose stored value exceeds `Number.MAX_SAFE_INTEGER` — e.g. a high-resolution epoch-nanosecond timestamp, a 64-bit counter that grew past 2^53, or a row written under a schema that used INTEGER for a value better stored as TEXT/bigint. Fires whether the value arrived as a JS number (unsafe) or as a bigint (out of range).","commonSituations":"Persisting nanosecond timestamps in an INTEGER column; counters that legitimately exceed 2^53 (lifetime byte counts after a long run); better-sqlite3 with `safeIntegers(true)` returning bigints for columns that were previously small numbers; schema migrations that widened a column's value range.","solutions":["Store the large value as TEXT or handle it as bigint end-to-end — do not round-trip it through `number`.","Use `nonNegativeIntegerFromBigInt` only after confirming the value fits in the safe range; otherwise keep it as bigint.","If the column represents a timestamp, switch to milliseconds (or store as TEXT ISO-8601).","Add a CHECK constraint at the SQLite layer to prevent out-of-range writes."],"exampleFix":"// before\nconst occurredAt = safeIntegerFromSql(row.occurredAtNs, 'occurredAt')  // ns > 2^53\n// after\nconst occurredAt = Math.floor(Number(row.occurredAtNs / 1_000_000n))  // ns -> ms","handlingStrategy":"validation","validationCode":"function fitsSafeInteger(v: bigint | number): boolean {\n  if (typeof v === 'number') return Number.isSafeInteger(v)\n  return v >= BigInt(Number.MIN_SAFE_INTEGER) && v <= BigInt(Number.MAX_SAFE_INTEGER)\n}","typeGuard":"function isSafeIntegerValue(v: unknown): v is number {\n  if (typeof v === 'number') return Number.isSafeInteger(v)\n  if (typeof v === 'bigint')\n    return v >= BigInt(Number.MIN_SAFE_INTEGER) && v <= BigInt(Number.MAX_SAFE_INTEGER)\n  return false\n}","tryCatchPattern":"try {\n  safeIntegerFromSql(row.col, 'col')\n} catch (err) {\n  if (err instanceof RangeError && err.message.endsWith('exceeds the JavaScript safe integer range')) {\n    // keep as bigint or re-scale units instead of converting\n  } else throw err\n}","preventionTips":["Do not store nanosecond timestamps or 64-bit counters as JS numbers.","Keep `safeIntegers(true)` on for big columns and handle them as bigint throughout.","Add schema CHECK constraints that keep INTEGER columns inside the safe range when they will be read as numbers."],"tags":["validation","range-error","sqlite","bigint","numbers"],"backgroundTag":null,"analyzedSha":"1a708ee57746c434e2c67a44bbf0906a976afea4","analyzedAt":"2026-08-12T16:18:09.346Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}