abhigyanpatwari/GitNexus · error

[embed] Failed to delete stale embedding rows — aborting to…

Error message

[embed] Failed to delete stale embedding rows — aborting to prevent vector-index corruption: ${msg}

What it means

Thrown by deleteStaleEmbeddingRows() during the incremental re-embed path: nodes whose contentHash changed must have their old Embedding rows DELETEd before re-embedding. Any DELETE failure other than a tolerated 'does not exist' (fresh index, table missing) aborts the pipeline, because leaving stale vectors would make the vector index return embeddings that no longer match node content — corruption by design is worse than stopping.

Solutions

  1. Stop other gitnexus processes using this repo's index (gitnexus serve, MCP server, another analyze) and rerun the embedding pipeline.
  2. Free disk space and verify write permissions on the .gitnexus directory.
  3. If the DB is corrupted, delete the .gitnexus index and re-run analyze --embeddings from scratch.
  4. Rerun the pipeline — the delete/re-embed is designed so a clean rerun converges.

Example fix

# before: serve is running while re-embedding
npx gitnexus serve &
npx gitnexus analyze --embeddings
# after: single writer at a time
kill %1  # stop serve first
npx gitnexus analyze --embeddings
npx gitnexus serve
Defensive patterns

Strategy: retry

Validate before calling

// ensure single writer before running the embedding pipeline
import { access, constants } from 'node:fs/promises';
await access('.gitnexus', constants.W_OK); // fail fast if index dir not writable

Type guard

const isStaleDeleteAbort = (e: unknown): boolean =>
  e instanceof Error && e.message.startsWith('[embed] Failed to delete stale embedding rows');

Try / catch

try {
  await runEmbeddingPipeline(executeQuery, executeWithReusedStatement, onProgress, config);
} catch (e) {
  if (isStaleDeleteAbort(e)) {
    // stop other gitnexus processes on this repo, then rerun the pipeline
  } else throw e;
}

Prevention

When it happens

Trigger: Running the embedding pipeline in incremental mode (changed files only) while the LadybugDB file is locked by another process (e.g. a concurrent `gitnexus serve` or second analyze), on a disk I/O error, or against a corrupted .gitnexus database during the MATCH (e:Embedding {nodeId}) DELETE e batch.

Common situations: Two gitnexus processes sharing one repo index, an editor MCP server holding the DB while the CLI re-embeds, full disk, or a DB left dirty after a killed run.

Related errors


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

Appendix: source

Thrown at gitnexus/src/core/embeddings/embedding-pipeline.ts:510

 * interleaving bounds that window to a single batch.
 */
const deleteStaleEmbeddingRows = async (
  executeWithReusedStatement: (
    cypher: string,
    paramsList: Array<Record<string, any>>,
  ) => Promise<void>,
  nodeIds: string[],
): Promise<void> => {
  if (nodeIds.length === 0) return;
  try {
    await executeWithReusedStatement(
      `MATCH (e:${EMBEDDING_TABLE_NAME} {nodeId: $nodeId}) DELETE e`,
      nodeIds.map((nodeId) => ({ nodeId })),
    );
  } catch (err) {
    const msg = err instanceof Error ? err.message : String(err);
    if (!msg.includes('does not exist')) {
      throw new Error(
        `[embed] Failed to delete stale embedding rows — aborting to prevent vector-index corruption: ${msg}`,
      );
    }
  }
};

/**
 * Run the embedding pipeline
 *
 * @param executeQuery - Function to execute Cypher queries against LadybugDB
 * @param executeWithReusedStatement - Function to execute with reused prepared statement
 * @param onProgress - Callback for progress updates
 * @param config - Optional configuration override
 * @param skipNodeIds - Optional set of node IDs that already have embeddings (incremental mode)
 * @param existingEmbeddings - Optional map of nodeId → contentHash for incremental mode.
 *        Nodes whose hash matches are skipped; nodes with a changed hash are DELETE'd
 *        and re-embedded; nodes not in the map are embedded fresh.
 */

View on GitHub (pinned to ac9a4e9abd)