abhigyanpatwari/GitNexus · error

Prepare failed

Error message

Prepare failed: ${errMsg}

What it means

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.

Solutions

  1. Read the appended engine message — it names the parser error and the offending token or table
  2. If the table is missing because the index predates a schema-changing version, re-run gitnexus analyze to rebuild it
  3. Check every $placeholder has a matching params key (and vice versa) before calling
  4. Escape reserved table names with backticks (escapeTableName) and use exact schema spellings for properties

Example fix

// before — placeholder does not match the params key
await executePrepared('MATCH (f:File) WHERE f.path = $path RETURN f', { filePath });

// after — placeholder names must match params keys exactly
await executePrepared('MATCH (f:File) WHERE f.path = $path RETURN f', { path: filePath });
Defensive patterns

Strategy: validation

Validate before calling

// validate placeholders and params keys line up before preparing
const placeholders = [...cypher.matchAll(/\$(\w+)/g)].map((m) => m[1]);
const missing = placeholders.filter((p) => !(p in params));
if (missing.length > 0) {
  throw new Error(`params missing keys used by the query: ${missing.join(', ')}`);
}

Type guard

const isPrepareFailed = (e: unknown): boolean =>
  e instanceof Error && e.message.startsWith('Prepare failed:');

Try / catch

try {
  rows = await executePrepared(cypher, params);
} catch (e) {
  if (isPrepareFailed(e)) {
    // parser rejected the statement — surface the engine text, do not retry the same string
    throw new Error(`bad Cypher (${e.message}); query: ${cypher.slice(0, 120)}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-08-20). Data as JSON: /api/errors/dc19b1705f1dbc79. Report an issue: GitHub.

Appendix: source

Thrown at gitnexus/src/core/lbug/lbug-adapter.ts:1910

/**
 * Execute a single parameterized query (prepare/execute pattern).
 * Prevents Cypher injection by binding values as parameters.
 */
export const executePrepared = async (
  cypher: string,
  params: Record<string, any>,
): Promise<any[]> => {
  // A `.length` compare on text we already hold; never throws (#2915).
  warnIfQueryTextUnbounded(cypher, 'executePrepared', (message) => logger.warn(message));
  const c = conn;
  if (!c) {
    throw new Error('LadybugDB not initialized. Call initLbug first.');
  }
  return withConnLock(async () => {
    const stmt = await c.prepare(cypher);
    if (!stmt.isSuccess()) {
      const errMsg = await stmt.getErrorMessage();
      throw new Error(`Prepare failed: ${errMsg}`);
    }
    const queryResult = await c.execute(stmt, params);
    return await readQueryRows(queryResult);
  });
};

export const executeWithReusedStatement = async (
  cypher: string,
  paramsList: Array<Record<string, any>>,
): Promise<void> => {
  const c = conn;
  if (!c) {
    throw new Error('LadybugDB not initialized. Call initLbug first.');
  }
  if (paramsList.length === 0) return;

  const SUB_BATCH_SIZE = 4;
  for (const [subBatchIndex, subBatch] of chunk(paramsList, SUB_BATCH_SIZE).entries()) {

View on GitHub (pinned to ac9a4e9abd)