abhigyanpatwari/GitNexus · error · Error

Cannot repair FTS indexes: the index is mid-incremental-reco

Error message

Cannot repair FTS indexes: the index is mid-incremental-recovery (a previous analyze run did not complete cleanly). Run `gitnexus analyze` first — it recovers the index automatically — then retry `--repair-fts`.

What it means

Thrown when `gitnexus analyze --repair-fts` is run while the repository's metadata carries an `incrementalInProgress` dirty flag — meaning a previous analyze run died mid-writeback. The guard deliberately refuses to open the database because replaying the possibly-poisoned WAL of a half-written graph before dirty-state recovery runs would either crash the process or certify FTS indexes over an inconsistent graph. The early-return nature of the FTS-only path means the sidecar-quarantine logic further down would never execute, so this throw is the only thing preventing an unsafe open.

Source

Thrown at gitnexus/src/core/run-analyze.ts:1124

  const existingMeta = await loadMeta(metaDir);

  // ── FTS-only repair path ────────────────────────────────────────────
  if (options.repairFts) {
    if (!existingMeta) {
      throw new Error(
        'Cannot repair FTS indexes because this repository has not been analyzed yet. ' +
          'Run `gitnexus analyze` first to create the initial index, then retry `--repair-fts`.',
      );
    }
    if (existingMeta.incrementalInProgress) {
      // #2409 / tri-review 4669518496 (R6): a dirty flag means the previous
      // run died mid-writeback — the graph may be half-written and its WAL
      // possibly poisoned. This branch returns early, so the dirty-recovery
      // sidecar quarantine below would never run: repairing FTS now would
      // open the DB and replay that WAL pre-quarantine, and even a
      // survivable open would certify FTS over a half-written graph.
      throw new Error(
        'Cannot repair FTS indexes: the index is mid-incremental-recovery ' +
          '(a previous analyze run did not complete cleanly). ' +
          'Run `gitnexus analyze` first — it recovers the index automatically — ' +
          'then retry `--repair-fts`.',
      );
    }
    let lbugStat;
    try {
      lbugStat = await fs.lstat(lbugPath);
    } catch {
      throw new Error(
        `Cannot repair FTS indexes: graph store at ${lbugPath} is missing. ` +
          'Run `gitnexus analyze` (full) to rebuild from scratch.',
      );
    }
    if (!lbugStat.isFile()) {
      const foundType = lbugStat.isDirectory()
        ? 'a directory'

View on GitHub (pinned to d540b00184)

Solutions

  1. Run `gitnexus analyze` without `--repair-fts` — the normal analyze path detects the dirty flag, quarantines the poisoned sidecars, and performs a full rebuild automatically.
  2. After the clean analyze completes, optionally run `gitnexus analyze --repair-fts` if keyword search is still degraded.

Example fix

// before
gitnexus analyze --repair-fts  // fails: incrementalInProgress dirty flag
// after
gitnexus analyze               // recovers the dirty index automatically
gitnexus analyze --repair-fts  // now safe to repair FTS
Defensive patterns

Strategy: validation

Validate before calling

// Before calling the repair-fts path, check the dirty flag:
import { loadMeta } from './storage/repo-manager.js';
const meta = await loadMeta(metaDir);
if (meta?.incrementalInProgress) {
  console.error('Index has a dirty incrementalInProgress flag. Run `gitnexus analyze` first to recover.');
  process.exit(1);
}

Type guard

// Guard against a dirty incremental flag before entering repair-fts:
const isCleanForFtsRepair = (meta: RepoMeta | undefined): boolean =>
  !!meta && !meta.incrementalInProgress && !!meta.stats;

Try / catch

// The CLI handler wraps runAnalyze in a try-catch; for programmatic use:
try {
  await runAnalyze({ ...options, repairFts: true });
} catch (err) {
  if (err instanceof Error && err.message.includes('mid-incremental-recovery')) {
    console.error('Run `gitnexus analyze` first to clear the dirty flag, then retry --repair-fts.');
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling `runAnalyze` (or the CLI `analyze --repair-fts`) when `existingMeta.incrementalInProgress` is truthy. This happens after an incremental analyze run was killed (OOM, SIGKILL, power loss, CI timeout) before it could clear its writeback-completion flag.

Common situations: A CI pipeline or IDE-integrated MCP server killed an incremental `gitnexus analyze` mid-write (timeout, OOM kill); the operator then runs `gitnexus analyze --repair-fts` to fix search without first running a normal analyze, hitting the dirty-flag gate.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/37dd64b3350389b6. Report an issue: GitHub.