tursodatabase/turso · error · TypeError
Only finite numbers (not Infinity or NaN) can be passed as a
Error message
Only finite numbers (not Infinity or NaN) can be passed as arguments
What it means
The JavaScript driver converts bind values into SQLite types before executing statements. SQLite numbers are 64-bit IEEE floats or signed 64-bit integers, so Infinity and NaN have no representation. normalizeBatchBindValue rejects them eagerly with a TypeError instead of silently corrupting the stored value.
Source
Thrown at bindings/javascript/packages/common/promise.ts:916
}
} catch (err) {
if (wrap) {
try {
await runRawSql("ROLLBACK");
} catch (rollbackError) {
throw attachRollbackError(err, rollbackError);
}
}
throw err;
}
return results;
}
function normalizeBatchBindValue(value: any): any {
if (value === null || value === undefined) return null;
if (typeof value === "number") {
if (!Number.isFinite(value)) {
throw new TypeError("Only finite numbers (not Infinity or NaN) can be passed as arguments");
}
return value;
}
if (typeof value === "bigint") {
if (value < -(1n << 63n) || value > (1n << 63n) - 1n) {
throw new TypeError("BigInt value is outside SQLite's signed 64-bit integer range");
}
return value;
}
if (
typeof value === "boolean" ||
typeof value === "string" ||
(ArrayBuffer.isView(value) && !(value instanceof DataView))
) {
return value;
}
if (value instanceof ArrayBuffer) return new Uint8Array(value);
return String(value);View on GitHub (pinned to c1e5928725)
Solutions
- Fix the caller code so the bound value is finite: handle or clamp Infinity/NaN before the batch call.
- Bind null instead when the value is not finite.
- If a large sentinel was intended, bind a finite literal or a string instead of Infinity.
- Store as TEXT if you genuinely need to persist Infinity-like values.
Example fix
// before const ratio = total === 0 ? Infinity : total / count; await db.batch([stmt.bind(ratio)]); // after const ratio = total === 0 ? null : total / count; await db.batch([stmt.bind(ratio)]);
Defensive patterns
Strategy: validation
Validate before calling
function isFiniteBind(v) { return v === null || v === undefined || (typeof v === 'number' && Number.isFinite(v)) || typeof v === 'bigint' || typeof v === 'boolean' || typeof v === 'string' || (v instanceof Date && Number.isFinite(v.getTime())) || v instanceof Uint8Array; }
if (!args.every(isFiniteBind)) throw new TypeError('bind args must be finite'); Type guard
const isBindableNumber = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v);
Try / catch
try { await db.batch(stmts); } catch (e) { if (e instanceof TypeError && /finite numbers/.test(e.message)) { /* sanitize args and retry with nulls */ } else throw e; } Prevention
- Sanitize numeric inputs (guard division by zero, NaN from Math) before building bind args.
- Write a bind-arg validator helper and run it at the boundary of your data layer.
- Treat Infinity/NaN as null at serialization time (like JSON does).
- Add unit tests covering degenerate numeric inputs.
When it happens
Trigger: Calling db.batch() (or any batch path that runs normalizeBatchBindValue) with a parameter that is Infinity, -Infinity, or NaN, e.g. binding 1/0 or NaN computed earlier in the pipeline.
Common situations: Dividing by zero before binding, Math.log(-1), JSON parsing of 'Infinity' (JSON.stringify turns it into null but arithmetic on sparse data yields NaN), passing an unset accumulator variable initialized to Infinity.
Related errors
- BigInt value is outside SQLite's signed 64-bit integer range
- Unknown parameter name: ${name}
- Unsupported parameter type: ${typeof value}
- HTTP request missing URL: no URL in request and no baseUrl i
- Index out of bound: {}
AI-assisted analysis of tursodatabase/turso@c1e5928725 (2026-08-31).
Data as JSON: /api/errors/752beda2742b10c6.
Report an issue: GitHub.