{"record":{"id":"1f3ae3db6f666846","repo":"abhigyanpatwari/GitNexus","slug":"batch-execution-failed-for-rows-firstrow-1","errorCode":null,"errorMessage":"Batch execution failed for rows ${firstRow + 1}-${firstRow + subBatch.length}: ${msg} (${queryPreview})","messagePattern":"Batch execution failed for rows (.+?)-(.+?): (.+?) \\((.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/lbug/lbug-adapter.ts","lineNumber":1947,"sourceCode":"    const firstRow = subBatchIndex * SUB_BATCH_SIZE;\n    // One critical section per sub-batch: the prepare + its executes run with\n    // exclusive access to the connection (so the WAL checkpoint driver cannot\n    // interleave a CHECKPOINT mid-batch), while the lock is released between\n    // sub-batches to let the driver checkpoint during a long writeback.\n    await withConnLock(async () => {\n      const stmt = await c.prepare(cypher);\n      if (!stmt.isSuccess()) {\n        const errMsg = await stmt.getErrorMessage();\n        throw new Error(`Prepare failed: ${errMsg}`);\n      }\n      try {\n        for (const params of subBatch) {\n          await drainQueryResult(await c.execute(stmt, params));\n        }\n      } catch (e) {\n        const msg = e instanceof Error ? e.message : String(e);\n        const queryPreview = cypher.replace(/\\s+/g, ' ').slice(0, 120);\n        throw new Error(\n          `Batch execution failed for rows ${firstRow + 1}-${firstRow + subBatch.length}: ${msg} (${queryPreview})`,\n        );\n      }\n      // Note: LadybugDB PreparedStatement doesn't require explicit close()\n    });\n  }\n};\n\n/**\n * Node and edge totals for the open index.\n *\n * `edges` is `undefined` when the count could NOT BE TAKEN, and that is a\n * different fact from zero. It used to be initialised to 0 with the query in a\n * swallowing `catch`, so a WAL/lock contention throw during finalize — a\n * documented hazard on this exact call — returned a measured-looking 0. The\n * collapse check downstream then read a perfectly healthy index as a total\n * write collapse, which is precisely the confident-zero failure that check\n * exists to prevent.","sourceCodeStart":1929,"sourceCodeEnd":1965,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/ac9a4e9abd8fd3058c070b72c23402a4f887929a/gitnexus/src/core/lbug/lbug-adapter.ts#L1929-L1965","documentation":"executeWithReusedStatement (gitnexus/src/core/lbug/lbug-adapter.ts:1835) wraps the per-row execute/drain loop in 4-row sub-batches. When the native engine throws mid-sub-batch (type/constraint violation, lock or checkpoint IO error, read-only connection), the wrapper rethrows with the 1-based row range of the failing sub-batch and a 120-char collapsed preview of the Cypher. Earlier sub-batches are already committed — there is no cross-sub-batch transaction.","triggerScenarios":"Batch writeback where one row of paramsList violates the schema (wrong property type, null in a required field, oversized value), the disk fills, a WAL checkpoint IO error interleaves, or the connection is read-only.","commonSituations":"Incremental analyze writebacks on machines with aggressive antivirus or low disk; property types that changed between GitNexus versions while the old index kept the previous schema; batches built from unvalidated extracted data.","solutions":["Use the reported row range to inspect paramsList[firstRow-1 .. firstRow+3] for the offending value (type, null, size)","If the underlying message is an IO/lock class — free disk space, stop competing processes, then re-run","If the schema drifted, rebuild with gitnexus analyze --force so table definitions match the emitted rows","Fix the row builder producing malformed values, then re-run the analyze"],"exampleFix":"// before — malformed row surfaces mid-batch with only a row range\nawait executeWithReusedStatement(cypher, paramsList);\n\n// after — reject malformed rows before any sub-batch commits\nconst bad = paramsList.findIndex((p) => p.line !== undefined && typeof p.line !== 'number');\nif (bad !== -1) throw new Error(`paramsList[${bad}] has non-numeric line`);\nawait executeWithReusedStatement(cypher, paramsList);","handlingStrategy":"validation","validationCode":"// pre-validate row shapes so a bad row fails BEFORE any sub-batch commits\nfor (const [i, p] of paramsList.entries()) {\n  for (const [k, v] of Object.entries(p)) {\n    if (v === undefined) throw new Error(`paramsList[${i}].${k} is undefined`);\n  }\n}","typeGuard":"const isBatchExecutionFailed = (e: unknown): boolean =>\n  e instanceof Error && e.message.startsWith('Batch execution failed for rows ');","tryCatchPattern":"try {\n  await executeWithReusedStatement(cypher, paramsList);\n} catch (e) {\n  if (isBatchExecutionFailed(e)) {\n    const m = e.message.match(/rows (\\d+)-(\\d+)/);\n    const from = m ? Number(m[1]) - 1 : 0;\n    logger.error(`failing rows: ${JSON.stringify(paramsList.slice(from, from + 4))}`);\n  }\n  throw e;\n}","preventionTips":["Validate extracted values (types, nulls, sizes) before building the writeback batch","Monitor disk space during long writebacks — ENOSPC mid-batch is a common root cause","Remember earlier sub-batches are already committed: after a failure, plan for a full-rebuild rerun rather than resuming"],"tags":["gitnexus","ladybugdb","batch-write","writeback","partial-commit"],"backgroundTag":"batch-write-failed","analyzedSha":"ac9a4e9abd8fd3058c070b72c23402a4f887929a","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}