tursodatabase/turso · error · TypeError
Expected first argument to be an array of statements
Error message
Expected first argument to be an array of statements
What it means
Thrown by Database.batch() when the first argument is not an array. batch() expects an array of statements, each either a SQL string or an object { sql, args }, so passing a single statement, a variadic list, or a non-array (string, object, undefined) is rejected with this TypeError before any connection state is touched.
Source
Thrown at bindings/javascript/packages/common/compat.ts:293
if (stepResult === STEP_DONE) {
break;
}
if (stepResult === STEP_ROW) {
// For exec(), we don't need the row data, just continue
continue;
}
}
} finally {
exec.reset();
}
}
batch(
statements: Array<string | { sql: string; args?: any[] | Record<string, any> }>,
options?: BatchMode | BatchOptions,
): ResultSet[] {
if (!Array.isArray(statements)) {
throw new TypeError("Expected first argument to be an array of statements");
}
if (!this.open) {
throw new TypeError("The database connection is not open");
}
const { mode, raw } = normalizeBatchOptions(options);
const wrap = mode != null && !this.db.inTransaction();
if (wrap) {
this.exec(`BEGIN ${normalizeBatchMode(mode!)}`);
}
const results: ResultSet[] = [];
try {
for (const statement of statements) {
const sql = typeof statement === "string" ? statement : statement.sql;
const args = typeof statement === "string" ? undefined : statement.args;
const stmt = this.db.prepare(sql);
try {View on GitHub (pinned to bad083fafb)
Solutions
- Wrap statements in an array: db.batch(['INSERT ...', { sql: 'UPDATE ...', args: [id] }])
- Convert iterables explicitly: db.batch(Array.from(map.values()))
- Guard dynamic statement lists: if (!Array.isArray(stmts) || stmts.length === 0) skip
- Use a single prepare().run() when you only have one statement - batch is for groups
Example fix
// before
db.batch('DELETE FROM a; DELETE FROM b'); // single string -> TypeError
// after
db.batch(['DELETE FROM a', 'DELETE FROM b']); Defensive patterns
Strategy: type-guard
Validate before calling
if (!Array.isArray(statements)) {
statements = [statements]; // or throw with context
}
if (statements.length === 0) return [];
db.batch(statements); Type guard
type BatchStatement = string | { sql: string; args?: any[] | Record<string, any> };
function isBatchInput(v: unknown): v is BatchStatement[] {
return Array.isArray(v) && v.every((s) => typeof s === 'string' || (s != null && typeof s === 'object' && typeof s.sql === 'string'));
} Prevention
- Always construct batch input as an array literal, even for one statement
- Convert iterables with Array.from before batching
- Type the parameter as BatchStatement[] so TypeScript rejects bare strings
When it happens
Trigger: Calling db.batch('INSERT INTO t VALUES (1)') with a bare string instead of an array; calling db.batch(stmt1, stmt2) expecting variadic behavior; passing a generator or Set of statements; passing undefined because a build step produced no statements.
Common situations: Migrating from an API that accepts a single statement; building statements conditionally and forgetting to wrap them in an array; converting from a Map/generator without Array.from; off-by-one refactors where the array literal is dropped.
Related errors
- The supplied SQL string contains no statements
- Expected first argument to be a function
- Expected first argument to be a string
- Expected second argument to be an options object
- The database connection is not open
AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16).
Data as JSON: /api/errors/c5385315969dded9.
Report an issue: GitHub.