{"record":{"id":"dc19b1705f1dbc79","repo":"abhigyanpatwari/GitNexus","slug":"prepare-failed-errmsg","errorCode":null,"errorMessage":"Prepare failed: ${errMsg}","messagePattern":"Prepare failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/lbug/lbug-adapter.ts","lineNumber":1910,"sourceCode":"/**\n * Execute a single parameterized query (prepare/execute pattern).\n * Prevents Cypher injection by binding values as parameters.\n */\nexport const executePrepared = async (\n  cypher: string,\n  params: Record<string, any>,\n): Promise<any[]> => {\n  // A `.length` compare on text we already hold; never throws (#2915).\n  warnIfQueryTextUnbounded(cypher, 'executePrepared', (message) => logger.warn(message));\n  const c = conn;\n  if (!c) {\n    throw new Error('LadybugDB not initialized. Call initLbug first.');\n  }\n  return 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    const queryResult = await c.execute(stmt, params);\n    return await readQueryRows(queryResult);\n  });\n};\n\nexport const executeWithReusedStatement = async (\n  cypher: string,\n  paramsList: Array<Record<string, any>>,\n): Promise<void> => {\n  const c = conn;\n  if (!c) {\n    throw new Error('LadybugDB not initialized. Call initLbug first.');\n  }\n  if (paramsList.length === 0) return;\n\n  const SUB_BATCH_SIZE = 4;\n  for (const [subBatchIndex, subBatch] of chunk(paramsList, SUB_BATCH_SIZE).entries()) {","sourceCodeStart":1892,"sourceCodeEnd":1928,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/ac9a4e9abd8fd3058c070b72c23402a4f887929a/gitnexus/src/core/lbug/lbug-adapter.ts#L1892-L1928","documentation":"executePrepared (gitnexus/src/core/lbug/lbug-adapter.ts:1798) runs the prepare/execute pattern on the singleton writable connection. c.prepare(cypher) returned a non-success PreparedStatement, so the LadybugDB parser rejected the statement, and the engine's own error text is appended. This is a query-shape problem (syntax, unknown table/property, bad parameter usage), not an IO failure.","triggerScenarios":"Calling executePrepared(cypher, params) with Cypher that references a node or relationship table absent from the open index, a misspelled property, a syntax error, or $placeholders that do not match the keys of the params object.","commonSituations":"Schema drift — querying with a newer GitNexus version's table/property names against an index built by an older one; dynamically built queries with unescaped reserved identifiers; querying tables before analyze has created them.","solutions":["Read the appended engine message — it names the parser error and the offending token or table","If the table is missing because the index predates a schema-changing version, re-run gitnexus analyze to rebuild it","Check every $placeholder has a matching params key (and vice versa) before calling","Escape reserved table names with backticks (escapeTableName) and use exact schema spellings for properties"],"exampleFix":"// before — placeholder does not match the params key\nawait executePrepared('MATCH (f:File) WHERE f.path = $path RETURN f', { filePath });\n\n// after — placeholder names must match params keys exactly\nawait executePrepared('MATCH (f:File) WHERE f.path = $path RETURN f', { path: filePath });","handlingStrategy":"validation","validationCode":"// validate placeholders and params keys line up before preparing\nconst placeholders = [...cypher.matchAll(/\\$(\\w+)/g)].map((m) => m[1]);\nconst missing = placeholders.filter((p) => !(p in params));\nif (missing.length > 0) {\n  throw new Error(`params missing keys used by the query: ${missing.join(', ')}`);\n}","typeGuard":"const isPrepareFailed = (e: unknown): boolean =>\n  e instanceof Error && e.message.startsWith('Prepare failed:');","tryCatchPattern":"try {\n  rows = await executePrepared(cypher, params);\n} catch (e) {\n  if (isPrepareFailed(e)) {\n    // parser rejected the statement — surface the engine text, do not retry the same string\n    throw new Error(`bad Cypher (${e.message}); query: ${cypher.slice(0, 120)}`);\n  }\n  throw e;\n}","preventionTips":["Keep Cypher templates as constants co-versioned with the schema they target","Rebuild the index after upgrading GitNexus versions that change table or property names","Always bind values via $parameters instead of string interpolation"],"tags":["gitnexus","ladybugdb","cypher","query","prepare"],"backgroundTag":"query-parse-error","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"}