{"record":{"id":"6c5c897b6b243f85","repo":"tursodatabase/turso","slug":"batch-execution-failed","errorCode":null,"errorMessage":"Batch execution failed","messagePattern":"Batch execution failed","errorType":"exception","errorClass":"DatabaseError","httpStatus":null,"severity":"error","filePath":"serverless/javascript/src/session.ts","lineNumber":625,"sourceCode":"            nextNonAtomicIdx = idx + 1;\n          }\n          currentResultIdx = undefined;\n          break;\n        }\n        case 'step_error':\n          // Capture the first error from BEGIN, any user step, or COMMIT\n          // and keep draining so the trailing probe (and, in atomic mode,\n          // ROLLBACK) is still observed. Errors on the synthetic ROLLBACK\n          // step are suppressed — by the time it runs the transaction has\n          // already been undone and surfacing a ROLLBACK error would mask\n          // the real cause we already captured.\n          if (deferredError === null && entry.step !== rollbackIdx) {\n            deferredError = new DatabaseError(entry.error?.message || 'Batch execution failed', entry.error?.code);\n          }\n          currentResultIdx = undefined;\n          break;\n        case 'error':\n          throw new DatabaseError(entry.error?.message || 'Batch execution failed', entry.error?.code);\n      }\n    }\n\n    if (deferredError !== null) {\n      throw deferredError;\n    }\n\n    return results;\n  }\n\n  /**\n   * Execute a sequence of SQL statements separated by semicolons.\n   * \n   * @param sql - SQL string containing multiple statements separated by semicolons\n   * @returns Promise resolving when all statements are executed\n   */\n  async sequence(sql: string, queryOptions?: QueryOptions): Promise<void> {\n    const request: PipelineRequest = {","sourceCodeStart":607,"sourceCodeEnd":643,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/serverless/javascript/src/session.ts#L607-L643","documentation":"DatabaseError thrown from Session.batch() when a step of a batch fails on the server. In atomic mode the first error from BEGIN, any user step, or COMMIT is captured (deferredError) and re-thrown after the stream drains — so ROLLBACK and the trailing autocommit probe are still observed — while a fatal stream 'error' entry throws immediately. The literal text only appears for message-less errors.","triggerScenarios":"db.batch([...], 'immediate') where a mid-batch statement violates a constraint; any statement of a non-atomic batch failing; COMMIT itself failing in atomic mode (e.g. deferred foreign-key violations), after which earlier statements were rolled back.","commonSituations":"Bulk inserts hitting duplicate keys; batched migrations containing one bad statement; FK constraints enforced at COMMIT surprising 'atomic' batches; non-atomic batches leaving earlier statements committed after the failure (by design).","solutions":["Identify the failing statement from the server message/code and fix it or its data (ON CONFLICT, pre-validation)","Decide atomicity deliberately: pass a mode ('immediate', 'deferred', ...) for all-or-nothing, omit it when partial progress is acceptable","For constraint-heavy bulk loads, pre-check uniqueness/FK validity or use INSERT OR IGNORE/REPLACE explicitly"],"exampleFix":"// before\nawait db.batch([\n  \"INSERT INTO kv(k) VALUES ('a')\",\n  \"INSERT INTO kv(k) VALUES ('a')\", // UNIQUE violation -> Batch execution failed, atomic mode rolls back\n]);\n\n// after\nawait db.batch([\n  \"INSERT INTO kv(k) VALUES ('a')\",\n  \"INSERT INTO kv(k) VALUES ('a') ON CONFLICT(k) DO NOTHING\",\n], \"immediate\");","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"const isDatabaseError = (e: unknown): e is Error & { code?: string } =>\n  e instanceof Error && e.name === \"DatabaseError\";","tryCatchPattern":"try {\n  await db.batch(statements, \"immediate\");\n} catch (e) {\n  if (e instanceof Error && e.name === \"DatabaseError\") {\n    // atomic mode: nothing was committed — safe to fix and rerun the batch.\n    // non-atomic mode: earlier statements ARE committed — reconcile before rerun.\n    console.error(\"batch failed:\", (e as { code?: string }).code, e.message);\n  }\n  throw e;\n}","preventionTips":["Pass an explicit mode when you need all-or-nothing semantics; omit it only when partial progress is acceptable","Add ON CONFLICT clauses for bulk loads that may contain duplicates","Never mix transaction-control SQL (BEGIN/COMMIT/SAVEPOINT) into the statements array — it breaks the wrapper's atomicity contract"],"tags":["batch","sql","transaction","javascript"],"backgroundTag":"sql-execution-error","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}