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

  1. Audit every code path that mutates the `current` accumulator — `saturatingAddSignedInt64` should be the only mutator.
  2. Recompute the corrupted counter from durable source-of-truth data (engine snapshot) and replace it before calling again.
  3. If the value legitimately could be that large, reconsider the storage type — the SQLite INTEGER column is the binding constraint.
  4. 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

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


AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12). Data as JSON: /api/errors/4a5202e6ceec9d15. Report an issue: GitHub.