{"record":{"id":"a830b5616339b846","repo":"tursodatabase/turso","slug":"expected-first-argument-to-be-an-array-of-statemen-a830b5","errorCode":null,"errorMessage":"Expected first argument to be an array of statements","messagePattern":"Expected first argument to be an array of statements","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"serverless/javascript/src/connection.ts","lineNumber":316,"sourceCode":"   *\n   * @example\n   * // Atomic via the mode parameter.\n   * await db.batch([\n   *   { sql: \"INSERT INTO users(name) VALUES (?)\", args: [\"Eve\"] },\n   *   { sql: \"INSERT INTO users(name) VALUES (?)\", args: [\"Frank\"] },\n   * ], \"immediate\");\n   *\n   * @example\n   * // Atomic via the transactionAsync() API for mixed workloads.\n   * const txn = db.transactionAsync(async (tx) => {\n   *   await tx.batch([{ sql: \"INSERT INTO users(name) VALUES (?)\", args: [\"Eve\"] }]);\n   *   await tx.run(\"UPDATE counters SET n = n + 1\");\n   * });\n   * await txn.immediate();\n   */\n  async batch(statements: BatchStatement[], options?: BatchMode | BatchOptions, queryOptions?: QueryOptions): Promise<any> {\n    if (!Array.isArray(statements)) {\n      throw new TypeError(\"Expected first argument to be an array of statements\");\n    }\n    if (!this.isOpen) {\n      throw new TypeError(\"The database connection is not open\");\n    }\n    await this.execLock.acquire();\n    try {\n      const { mode, raw } = normalizeBatchOptions(options);\n      // Inside an outer transaction(...) callback the surrounding BEGIN\n      // already opened a transaction on this stream; emitting another\n      // `BEGIN` step would fail, so ignore the user-supplied mode.\n      const effectiveMode = this.session.inTransaction ? undefined : mode;\n      const results = await this.session.batch(\n        statements,\n        effectiveMode,\n        queryOptions,\n        this.defaultSafeIntegerMode,\n        raw,\n      );","sourceCodeStart":298,"sourceCodeEnd":334,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/serverless/javascript/src/connection.ts#L298-L334","documentation":"Connection.batch() validates its first argument with Array.isArray and throws a plain TypeError when it is not an array. Notably this check runs before the isOpen check, so a non-array argument raises this TypeError even on a closed connection. It mirrors the compat layer and better-sqlite3 convention that batch takes only arrays of statements.","triggerScenarios":"db.batch({ sql: 'SELECT 1' }) with a bare object; db.batch(undefined) when a statement-building function returns nothing; db.batch(promisedArray) without await; passing a SQL string directly.","commonSituations":"Converting sequential run() calls into a batch and forgetting the array literal; conditional statement lists that collapse to undefined; JS code without TypeScript catching the shape; spread of a non-iterable into the argument.","solutions":["Pass an array: db.batch([{ sql: 'INSERT INTO t VALUES (?)', args: [1] }], 'write')","Normalize: db.batch(Array.isArray(stmts) ? stmts : [stmts])","Type the variable as BatchStatement[] to catch it at compile time","Await async statement builders before passing their result"],"exampleFix":"// before\nawait db.batch({ sql: 'INSERT INTO t VALUES (?)', args: [1] });\n// TypeError: Expected first argument to be an array of statements\n\n// after\nawait db.batch([{ sql: 'INSERT INTO t VALUES (?)', args: [1] }]);","handlingStrategy":"type-guard","validationCode":"function toBatchStatements(v: BatchStatement[] | BatchStatement | undefined): BatchStatement[] {\n  if (v === undefined) return [];\n  return Array.isArray(v) ? v : [v];\n}\n\nawait db.batch(toBatchStatements(stmts), 'write');","typeGuard":"function isBatchStatementArray(v: unknown): v is BatchStatement[] {\n  return Array.isArray(v) && v.every((s) => typeof s === 'string' || (typeof s === 'object' && s !== null && 'sql' in s));\n}","tryCatchPattern":"try {\n  await db.batch(stmts);\n} catch (e) {\n  if (e instanceof TypeError && e.message.includes('array of statements')) {\n    throw new TypeError('db.batch expects an array — got ' + typeof stmts);\n  }\n  throw e;\n}","preventionTips":["Type batch inputs as BatchStatement[] everywhere they are built","Wrap single statements in brackets when converting sequential run() calls to a batch","Await async statement builders before passing results to batch()","Test batch construction helpers with empty and single-statement cases"],"tags":["validation","typeerror","batch","api-misuse"],"backgroundTag":"invalid-argument-type","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}