{"record":{"id":"37dd64b3350389b6","repo":"abhigyanpatwari/GitNexus","slug":"cannot-repair-fts-indexes-the-index-is-mid-increm","errorCode":null,"errorMessage":"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`.","messagePattern":"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`\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/run-analyze.ts","lineNumber":1124,"sourceCode":"\n  const existingMeta = await loadMeta(metaDir);\n\n  // ── FTS-only repair path ────────────────────────────────────────────\n  if (options.repairFts) {\n    if (!existingMeta) {\n      throw new Error(\n        'Cannot repair FTS indexes because this repository has not been analyzed yet. ' +\n          'Run `gitnexus analyze` first to create the initial index, then retry `--repair-fts`.',\n      );\n    }\n    if (existingMeta.incrementalInProgress) {\n      // #2409 / tri-review 4669518496 (R6): a dirty flag means the previous\n      // run died mid-writeback — the graph may be half-written and its WAL\n      // possibly poisoned. This branch returns early, so the dirty-recovery\n      // sidecar quarantine below would never run: repairing FTS now would\n      // open the DB and replay that WAL pre-quarantine, and even a\n      // survivable open would certify FTS over a half-written graph.\n      throw new Error(\n        'Cannot repair FTS indexes: the index is mid-incremental-recovery ' +\n          '(a previous analyze run did not complete cleanly). ' +\n          'Run `gitnexus analyze` first — it recovers the index automatically — ' +\n          'then retry `--repair-fts`.',\n      );\n    }\n    let lbugStat;\n    try {\n      lbugStat = await fs.lstat(lbugPath);\n    } catch {\n      throw new Error(\n        `Cannot repair FTS indexes: graph store at ${lbugPath} is missing. ` +\n          'Run `gitnexus analyze` (full) to rebuild from scratch.',\n      );\n    }\n    if (!lbugStat.isFile()) {\n      const foundType = lbugStat.isDirectory()\n        ? 'a directory'","sourceCodeStart":1106,"sourceCodeEnd":1142,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/gitnexus/src/core/run-analyze.ts#L1106-L1142","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Run `gitnexus analyze` without `--repair-fts` — the normal analyze path detects the dirty flag, quarantines the poisoned sidecars, and performs a full rebuild automatically.","After the clean analyze completes, optionally run `gitnexus analyze --repair-fts` if keyword search is still degraded."],"exampleFix":"// before\ngitnexus analyze --repair-fts  // fails: incrementalInProgress dirty flag\n// after\ngitnexus analyze               // recovers the dirty index automatically\ngitnexus analyze --repair-fts  // now safe to repair FTS","handlingStrategy":"validation","validationCode":"// Before calling the repair-fts path, check the dirty flag:\nimport { loadMeta } from './storage/repo-manager.js';\nconst meta = await loadMeta(metaDir);\nif (meta?.incrementalInProgress) {\n  console.error('Index has a dirty incrementalInProgress flag. Run `gitnexus analyze` first to recover.');\n  process.exit(1);\n}","typeGuard":"// Guard against a dirty incremental flag before entering repair-fts:\nconst isCleanForFtsRepair = (meta: RepoMeta | undefined): boolean =>\n  !!meta && !meta.incrementalInProgress && !!meta.stats;","tryCatchPattern":"// The CLI handler wraps runAnalyze in a try-catch; for programmatic use:\ntry {\n  await runAnalyze({ ...options, repairFts: true });\n} catch (err) {\n  if (err instanceof Error && err.message.includes('mid-incremental-recovery')) {\n    console.error('Run `gitnexus analyze` first to clear the dirty flag, then retry --repair-fts.');\n  }\n  throw err;\n}","preventionTips":["Always run `gitnexus analyze` (not `--repair-fts`) after a crashed or killed run — the normal path handles dirty-state recovery automatically.","Monitor CI/analyze runs for exit-code abnormalities and always follow up a killed run with a clean `gitnexus analyze` before using FTS-repair shortcuts.","Never use `--repair-fts` as a substitute for a normal analyze after a crash."],"tags":["fts","analyze","crash-recovery","incremental","config"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}