tursodatabase/turso · error · TypeError

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

Error message

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

What it means

During client.batch(), each statement's args are normalized (converts JS bind values to the wire format). If normalization throws for statement at zero-based index i, the library rethrows batchInputError(i, error) producing 'batch statement i failed: <message>' so the caller knows which statement contained the unencodable argument.

Source

Thrown at bindings/javascript/packages/common/promise.ts:799

      exec.reset();
    }
  };

  const { mode, raw } = normalizeBatchOptions(options);
  const wrap = mode != null && !native.inTransaction();
  const normalizedStatements = statements.map((statement, index): BatchStatement => {
    if (typeof statement === "string" || statement.args === undefined) {
      return statement;
    }
    try {
      const args = Array.isArray(statement.args)
        ? statement.args.map(normalizeBatchBindValue)
        : Object.fromEntries(
          Object.entries(statement.args).map(([name, value]) => [name, normalizeBatchBindValue(value)]),
        );
      return { sql: statement.sql, args };
    } catch (error) {
      throw batchInputError(index, error);
    }
  });
  if (wrap) {
    for (let index = 0; index < normalizedStatements.length; index++) {
      const statement = normalizedStatements[index];
      const sql = typeof statement === "string" ? statement : statement.sql;
      const keyword = firstSqlKeyword(sql);
      if (keyword !== undefined && TRANSACTION_CONTROL_KEYWORDS.has(keyword)) {
        throw batchInputError(index, new Error(`${keyword} is not allowed in an atomic batch`));
      }
    }
  }
  if (wrap) {
    await runRawSql(`BEGIN ${normalizeBatchMode(mode!)}`);
  }

  const results: ResultSet[] = [];
  const executeStatement = async (

View on GitHub (pinned to c1e5928725)

Solutions

  1. Read the index in the error message and inspect that statement's args for unsupported values.
  2. Coerce values to supported bind types: number, string, bigint (within i64), ArrayBuffer/Uint8Array, or null.
  3. Replace undefined with null explicitly before batching.
  4. Use normalize/sanitize helpers on the args array/object before calling batch().

Example fix

// before
await db.batch([{ sql: "INSERT INTO t VALUES (?)", args: [user.createdAt] }]); // Date/undefined
// after
const safe = (v) => v === undefined ? null : (v instanceof Date ? v.toISOString() : v);
await db.batch([{ sql: "INSERT INTO t VALUES (?)", args: [safe(user.createdAt)] }]);
Defensive patterns

Strategy: validation

Validate before calling

function isBindable(v) {
  return v === null || typeof v === 'number' || typeof v === 'string' ||
    (typeof v === 'bigint' && v >= -(2n**63n) && v < 2n**63n) ||
    v instanceof Uint8Array || v instanceof ArrayBuffer;
}
statements.forEach((s, i) => (Array.isArray(s.args) ? s.args : Object.values(s.args ?? {}))
  .forEach(v => { if (!isBindable(v)) throw new Error(`bad arg in statement ${i}: ${v}`); }));

Type guard

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

Try / catch

try {
  const results = await db.batch(statements);
} catch (e) {
  if (typeof e.message === 'string' && /batch statement \d+ failed/.test(e.message)) {
    const idx = Number(e.message.match(/\d+/)[0]);
    console.error(`Statement ${idx} has invalid args`, statements[idx].args);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling batch() with a statement whose args contain values that cannot be bound: unsupported JS types (undefined, objects, functions, BigInt out of range), invalid named-parameter containers, or normalizeBatchBindValue rejecting a value.

Common situations: Passing undefined from an unpopulated object field; passing a Date/class instance instead of a primitive; mixing named args object with array expectations; large BigInt values beyond i64 range.

Related errors


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