agalwood/Motrix · error · RangeError

${label} is not an integer

Error message

${label} is not an integer

What it means

Thrown by safeIntegerFromSql when a value read from a better-sqlite3 row is neither a number nor a bigint. The function exists to bridge SQLite safeIntegers() rows (which arrive as bigint) with JavaScript numbers; anything else means the column did not store an integer at all (e.g. text, null, blob, float). The label argument identifies which field failed so the message names the offending column.

Source

Thrown at src/core/lib/sqlite-integers.ts:14

/**
 * Conversions between better-sqlite3 `safeIntegers()` rows and JavaScript
 * numbers, shared by the SQLite-backed stores.
 */

export function safeIntegerFromSql(value: unknown, label: string): number {
  if (typeof value === 'number') {
    if (!Number.isSafeInteger(value)) {
      throw new RangeError(`${label} exceeds the JavaScript safe integer range`)
    }
    return value
  }
  if (typeof value !== 'bigint') {
    throw new RangeError(`${label} is not an integer`)
  }
  if (
    value < BigInt(Number.MIN_SAFE_INTEGER) ||
    value > BigInt(Number.MAX_SAFE_INTEGER)
  ) {
    throw new RangeError(`${label} exceeds the JavaScript safe integer range`)
  }
  return Number(value)
}

export function nonNegativeIntegerFromBigInt(
  value: bigint,
  label: string
): number {
  const converted = safeIntegerFromSql(value, label)
  if (converted < 0) {
    throw new RangeError(`${label} must be non-negative`)
  }

View on GitHub (pinned to 1a708ee577)

Solutions

  1. Check the SQLite schema (PRAGMA table_info) for the named column and ensure it has INTEGER affinity.
  2. Coalesce NULLs in the query (SELECT COALESCE(col, 0)) or guard before calling safeIntegerFromSql.
  3. If the column legitimately holds non-integer data, parse it explicitly (Number(row.col)) instead of routing through safeIntegerFromSql.
  4. Re-run the failing query in the sqlite3 CLI and inspect typeof() of the offending cell to confirm its storage class.

Example fix

// before
const id = safeIntegerFromSql(row.maybeNullId, 'maybeNullId')
// after
const id = safeIntegerFromSql(row.maybeNullId ?? 0, 'maybeNullId')
Defensive patterns

Strategy: validation

Validate before calling

function isSqliteIntegerLike(value: unknown): value is number | bigint {
  return typeof value === 'bigint' || (typeof value === 'number' && Number.isInteger(value))
}
// before calling safeIntegerFromSql:
if (!isSqliteIntegerLike(row.col)) {
  throw new Error(`column 'col' is not an integer; got ${typeof row.col}`)
}

Type guard

function isSqliteIntegerLike(value: unknown): value is number | bigint {
  return typeof value === 'bigint' || (typeof value === 'number' && Number.isInteger(value))
}

Try / catch

try {
  const id = safeIntegerFromSql(row.col, 'col')
} catch (e) {
  if (e instanceof RangeError && /is not an integer/.test(e.message)) {
    // handle non-integer cell
  } else throw e
}

Prevention

When it happens

Trigger: Calling safeIntegerFromSql(value, label) where value is a string, null, undefined, boolean, or object — i.e. a SQLite cell that was not declared/stored as INTEGER, or a NULL that was not coalesced before the call. Common when a schema migration left a column as TEXT or when a JOIN returns an unexpected NULL.

Common situations: Schema drift where a column type changed from INTEGER to TEXT; queries that SELECT an expression/alias whose SQLite affinity yields TEXT; nullable foreign-key columns that return NULL; loading a fixture or seed file whose numeric fields were quoted.

Related errors


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