agalwood/Motrix · error · RangeError
${label} must be non-negative
Error message
${label} must be non-negative What it means
Thrown by nonNegativeIntegerFromBigInt after safeIntegerFromSql succeeds but the resulting number is negative. The helper enforces a non-negative contract (counts, sizes, rowids) on top of the safe-integer conversion.
Source
Thrown at src/core/lib/sqlite-integers.ts:31
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`)
}
return converted
}
export function requireSafeTimestamp(value: number, label: string): void {
if (!Number.isSafeInteger(value)) {
throw new RangeError(`${label} must be a safe integer timestamp`)
}
}
export function requireSafePositiveTimestamp(
value: number,
label: string
): void {
if (!Number.isSafeInteger(value) || value <= 0) {
throw new RangeError(`${label} must be a positive safe integer timestamp`)
}
}View on GitHub (pinned to 1a708ee577)
Solutions
- Inspect the row that triggered it and find the writer that produced the negative value.
- Add a CHECK (col >= 0) constraint at the SQLite schema level to prevent future bad writes.
- If negatives are valid for this field, call safeIntegerFromSql directly instead of the non-negative variant.
- Clamp at the write site: UPDATE ... SET col = MAX(0, col - ?).
Example fix
// before const count = nonNegativeIntegerFromBigInt(row.delta, 'delta') // after — field is genuinely signed const delta = safeIntegerFromSql(row.delta, 'delta')
Defensive patterns
Strategy: validation
Validate before calling
function isNonNegativeSafeInteger(value: bigint): boolean {
return value >= 0n && value <= BigInt(Number.MAX_SAFE_INTEGER)
}
if (!isNonNegativeSafeInteger(row.count)) {
throw new Error(`count out of range: ${row.count}`)
} Type guard
function isNonNegativeSafe(value: unknown): value is number {
if (typeof value === 'bigint') return value >= 0n && value <= BigInt(Number.MAX_SAFE_INTEGER)
if (typeof value === 'number') return Number.isSafeInteger(value) && value >= 0
return false
} Try / catch
try {
const count = nonNegativeIntegerFromBigInt(row.count, 'count')
} catch (e) {
if (e instanceof RangeError && /non-negative/.test(e.message)) {
// log and clamp or reject the row
} else throw e
} Prevention
- Add CHECK (col >= 0) constraints in SQLite for count/size/offset columns.
- Audit decrement operations (UPDATE ... SET col = col - ?) and wrap with MAX(0, ...).
- Validate at the write boundary, not just the read boundary.
When it happens
Trigger: Calling nonNegativeIntegerFromBigInt(value, label) where value is a negative bigint or a negative in-range number; e.g. a column storing a signed delta that legitimately went below zero, or a corrupted rowid.
Common situations: A count/size/offset column that received a negative value due to a buggy increment; signed-vs-unsigned mismatch when importing data; underflow in a decrement operation that was written back to the DB.
Related errors
- current exceeds the signed int64 range
- ${label} is not an integer
- samples[${index}].flags exceeds the SQLite bound
- ${label} exceeds the JavaScript safe integer range
- ${label} must be a safe integer timestamp
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/01ea81f978dfd04f.
Report an issue: GitHub.