tursodatabase/turso · error · DatabaseError

batch statement ${index} failed: ${message}

Error message

batch statement ${index} failed: ${message}

What it means

In the serverless JS client's session.batch(), each statement's args are encoded client-side via encodeSqlArgs before anything is sent. If encoding throws (unsupported value types), the error is rethrown as batchInputError(index, message) with the statement's zero-based index; since nothing has executed, batchResults in the resulting DatabaseError is empty.

Source

Thrown at serverless/javascript/src/session.ts:521

    mode?: BatchMode,
    queryOptions?: QueryOptions,
    safeIntegers: boolean = false,
    raw: boolean = false,
  ): Promise<any> {
    const userSteps: BatchStep[] = statements.map((statement, index) => {
      if (typeof statement === 'string') {
        return {
          stmt: { sql: statement, args: [], named_args: [], want_rows: true },
        };
      }
      // A value that cannot be encoded fails client-side before anything
      // is sent; report it with the statement's index like any other
      // statement failure. Nothing has executed, so batchResults is empty.
      let encodedArgs;
      try {
        encodedArgs = encodeSqlArgs(statement.args ?? []);
      } catch (e: any) {
        throw batchInputError(index, e?.message ?? String(e));
      }
      return {
        stmt: {
          sql: statement.sql,
          args: encodedArgs.args,
          named_args: encodedArgs.namedArgs,
          want_rows: true,
        },
      };
    });

    if (mode !== undefined) {
      for (let index = 0; index < statements.length; index++) {
        const statement = statements[index];
        const sql = typeof statement === 'string' ? statement : statement.sql;
        const keyword = firstSqlKeyword(sql);
        if (keyword !== undefined && TRANSACTION_CONTROL_KEYWORDS.has(keyword)) {
          throw batchInputError(index, `${keyword} is not allowed in an atomic batch`);

View on GitHub (pinned to c1e5928725)

Solutions

  1. Use the batchIndex on the thrown DatabaseError to find the offending statement and fix its args.
  2. Convert values to supported types: null, number, string, bigint (i64 range), or Uint8Array.
  3. Replace undefined with explicit null; serialize Dates/objects to strings/JSON before batching.
  4. Encode args once yourself with the same encoder to validate before calling batch().

Example fix

// before
await session.batch([{ sql: "INSERT INTO t VALUES (?)", args: [meta.tags] }]); // undefined
// after
await session.batch([{ sql: "INSERT INTO t VALUES (?)", args: [meta.tags ?? null] }]);
Defensive patterns

Strategy: validation

Validate before calling

function isEncodable(v) {
  return v === null || typeof v === 'number' || typeof v === 'string' ||
    (typeof v === 'bigint' && v >= -(2n**63n) && v < 2n**63n) ||
    v instanceof Uint8Array;
}
statements.forEach((s, i) => (s.args ?? []).forEach(v => {
  if (!isEncodable(v)) throw new Error(`statement ${i}: unencodable arg ${v}`);
}));

Type guard

const isEncodable = (v: unknown): v is null | string | number | bigint | Uint8Array =>
  v === null || typeof v === 'number' || typeof v === 'string' ||
  (typeof v === 'bigint' && v >= -(2n**63n) && v < 2n**63n) ||
  v instanceof Uint8Array;

Try / catch

try {
  await session.batch(statements, mode);
} catch (e) {
  if (e?.batchIndex !== undefined) {
    console.error(`statement ${e.batchIndex} failed`, e.message, e.batchResults);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling session.batch() with a statement whose args array or named-args record contains values encodeSqlArgs cannot serialize: undefined, unsupported objects, invalid BigInt, wrong container type.

Common situations: Optional JS fields left undefined; sending class instances/Dates instead of primitives; passing null-like placeholder values the encoder rejects; refactored code where args switched between array and named-object form.

Related errors


AI-assisted analysis of tursodatabase/turso@c1e5928725 (2026-08-31). Data as JSON: /api/errors/69447e514cbe163c. Report an issue: GitHub.