agalwood/Motrix · critical · RangeError
current exceeds the signed int64 range
Error message
current exceeds the signed int64 range
What it means
`saturatingAddSignedInt64` adds a non-negative bigint `delta` to a non-negative bigint `current` and saturates at `MAX_SIGNED_SQLITE_INTEGER` (2^63-1, ~9.22e18). It throws this `RangeError` *before* adding if `current` alone already exceeds that bound — meaning the running counter is in a corrupted state the saturating helper was designed to prevent. Because `current` passed the immediately-preceding `assertNonNegativeBigInt`, a hit here indicates the counter was already poisoned upstream. The guard keeps SQLite 8-byte `INTEGER` columns in range.
Source
Thrown at src/core/inspector-activity/validators.ts:95
export function normalizeSpeed(value: number, label: string): number {
if (!Number.isFinite(value) || value < 0) {
throw new RangeError(`${label} must be finite and non-negative`)
}
const normalized = Math.round(value)
if (!Number.isSafeInteger(normalized)) {
throw new RangeError(`${label} exceeds the JavaScript safe integer range`)
}
return normalized
}
export function saturatingAddSignedInt64(
current: bigint,
delta: bigint
): { value: bigint; saturated: boolean } {
assertNonNegativeBigInt(current, 'current')
assertNonNegativeBigInt(delta, 'delta')
if (current > MAX_SIGNED_SQLITE_INTEGER) {
throw new RangeError('current exceeds the signed int64 range')
}
if (delta > MAX_SIGNED_SQLITE_INTEGER - current) {
return { value: MAX_SIGNED_SQLITE_INTEGER, saturated: true }
}
return { value: current + delta, saturated: false }
}
export function saturatingAddSafeInteger(
current: number,
delta: number
): { value: number; saturated: boolean } {
assertNonNegativeSafeInteger(current, 'current')
assertNonNegativeSafeInteger(delta, 'delta')
if (delta > MAX_SAFE_SQLITE_INTEGER - current) {
return { value: MAX_SAFE_SQLITE_INTEGER, saturated: true }
}
return { value: current + delta, saturated: false }
}View on GitHub (pinned to 1a708ee577)
Solutions
- Audit every code path that mutates the `current` accumulator — `saturatingAddSignedInt64` should be the only mutator.
- Recompute the corrupted counter from durable source-of-truth data (engine snapshot) and replace it before calling again.
- If the value legitimately could be that large, reconsider the storage type — the SQLite INTEGER column is the binding constraint.
- Add a regression test that drives the counter toward saturation and asserts it clamps rather than throws.
Example fix
// before
totalBytes = totalBytes + delta // totalBytes already > 2^63-1
// after
const { value } = saturatingAddSignedInt64(totalBytes, delta)
totalBytes = value Defensive patterns
Strategy: validation
Validate before calling
import { MAX_SIGNED_SQLITE_INTEGER } from '@core/inspector-activity/validators'
function guardAdd(current: bigint, delta: bigint): bigint {
if (current > MAX_SIGNED_SQLITE_INTEGER)
throw new RangeError(`current already corrupted: ${current}`)
return current + delta
} Type guard
import { MAX_SIGNED_SQLITE_INTEGER } from '@core/inspector-activity/validators'
function isSignedInt64Bigint(v: unknown): v is bigint {
return typeof v === 'bigint' && v >= 0n && v <= MAX_SIGNED_SQLITE_INTEGER
} Try / catch
try {
saturatingAddSignedInt64(current, delta)
} catch (err) {
if (err instanceof RangeError && err.message === 'current exceeds the signed int64 range') {
// recompute current from durable source before retrying
} else throw err
} Prevention
- Route every mutation of the byte counter through `saturatingAddSignedInt64` — never add to it directly.
- Treat a hit as data corruption, not a recoverable input error; recompute from durable state.
- Log the corrupted value to telemetry so the upstream double-count can be traced.
When it happens
Trigger: Calling `saturatingAddSignedInt64(current, delta)` where `current` is a bigint byte-counter (e.g. an `estimatedDownloadBytesDelta` accumulator) greater than `9_223_372_036_854_775_807n` (~8 EiB). Both inputs already passed the non-negative-bigint precondition, so this fires only when the cumulative counter is astronomically — and almost certainly wrongly — large.
Common situations: An upstream double-counting bug that increments the lifetime byte counter twice per sample; persisted state restored from a corrupted row; tests feeding a synthetic 2^64-scale value through without saturation; arithmetic that confused bytes with bits and shifted the magnitude.
Related errors
- ${label} exceeds the JavaScript safe integer range
- ${label} must be a non-negative bigint
- samples[${index}].flags exceeds the SQLite bound
- ${label} must be non-negative
- taskId must be a string
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/4a5202e6ceec9d15.
Report an issue: GitHub.