abhigyanpatwari/GitNexus · error · LbugWipeError

Cannot start dirty-state recovery — the interrupted run's La

Error message

Cannot start dirty-state recovery — the interrupted run's LadybugDB sidecars could neither be moved aside nor removed:

What it means

Thrown as an `LbugWipeError` during dirty-state recovery when `quarantineSidecarsForDirtyRecovery` reports `failed.length > 0` — the interrupted run's WAL/shadow/lock sidecars could neither be moved aside nor removed. Failing fast here (in seconds) with the same typed error the eventual DB-wipe would throw is strictly better than running the entire pipeline only to die at the wipe step, which would waste minutes and zero embeddings. The message is self-contained because the HTTP server forwards only `err.message` over worker IPC.

Source

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

          'from the interrupted run (the file could not be moved aside, so its bytes were ' +
          'removed — post-mortem forensics lost). Recovery proceeds with full embedding ' +
          'preservation.',
      );
    }
    if (failed.length > 0) {
      // FIX 1 (this shipping review, replacing the tri-review 4669518496
      // P2-3 drop-shape design): under a persistent lock the old drop-shape
      // run derived its embedding mode as "drop", ran the WHOLE pipeline,
      // and then died at the rebuild wipe on the very same handle — wasting
      // minutes and zeroing embeddings on the way. A possibly-poisoned
      // sidecar still sits next to the DB (any pre-wipe open would replay it
      // and die), so failing here, in seconds, with the same actionable
      // typed error the wipe would eventually throw is strictly better —
      // and the CLI's LbugWipeError handler already renders it
      // (recoveryHint 'lbug-wipe-failed'). The message is self-contained
      // (headline + paths + lock guidance) because serve forwards only
      // err.message over worker IPC.
      throw new LbugWipeError(failed, {
        headline:
          "Cannot start dirty-state recovery — the interrupted run's LadybugDB sidecars " +
          'could neither be moved aside nor removed:',
      });
    }
  }

  // ── pdg-mode flip forces full writeback (#2099 F1) ─────────────────
  // The incremental writeback persists only changed-file nodes, so a pdg
  // config differing from the one the DB rows were built under cannot be
  // reconciled incrementally: off→on silently drops the freshly built CFG
  // layer ("Incremental: changed=0", zero BasicBlock rows), on→off strands
  // zombie blocks for unchanged files. MUST sit before the alreadyUpToDate
  // fast path below — a clean-tree flip would otherwise early-return without
  // running the pipeline at all. The notice is deliberately NOT gated on
  // options.force: --skills implies force with no message of its own, and a
  // mode change deserves a diagnostic regardless of why a rebuild happens.
  if (existingMeta && pdgModeMismatch(existingMeta.pdg, options)) {

View on GitHub (pinned to d540b00184)

Solutions

  1. Close any other process that may have the database open: stop `gitnexus serve`, close IDE extensions, and kill stale `gitnexus` processes.
  2. Re-run `gitnexus analyze` immediately — the handle may have been released by now (the error message itself says 'an immediate re-run often succeeds').
  3. On Windows, wait a few seconds for antivirus/delete-pending handles to release, or exclude `.gitnexus/` from AV scanning.
  4. If the `.gitnexus` directory is on a network filesystem, move it to local storage or fix the mount's locking behavior.
  5. As a last resort, manually delete the sidecar files listed in the error (`.wal`, `.shadow`) and re-run.

Example fix

// before
gitnexus analyze
// LbugWipeError: Cannot start dirty-state recovery...could neither be moved aside nor removed:
//   - .gitnexus/store.lbug.wal
//   - .gitnexus/store.lbug.shadow
// after
# kill any process holding the handle
gitnexus analyze   # immediate re-run often succeeds
Defensive patterns

Strategy: retry

Validate before calling

// Before analyze, check for processes that might hold DB handles:
// (On Linux/Mac: lsof +D .gitnexus; on Windows: handle.exe or tasklist)
// Programmatically, check if the lock file is held:
import { existsSync } from 'fs';
if (existsSync(path.join(repoPath, '.gitnexus', 'store.lbug.lock'))) {
  console.warn('A lock file exists. Ensure no other gitnexus process is running.');
}

Type guard

import { isLbugWipeError } from './lbug/lbug-adapter.js';
// LbugWipeError is exported; check by name:
const isWipeError = (err: unknown): boolean =>
  err instanceof Error && err.name === 'LbugWipeError';

Try / catch

// Retry pattern — the error message itself says 'an immediate re-run often succeeds':
for (let attempt = 1; attempt <= 3; attempt++) {
  try {
    await runAnalyze(options);
    break;
  } catch (err) {
    if (err instanceof Error && err.name === 'LbugWipeError' && attempt < 3) {
      console.warn(`Wipe failed (attempt ${attempt}), retrying...`);
      await new Promise((r) => setTimeout(r, 2000));
      continue;
    }
    throw err;
  }
}

Prevention

When it happens

Trigger: `existingMeta.incrementalInProgress` is truthy (dirty flag from a crashed run), `quarantineSidecarsForDirtyRecovery(lbugPath, log)` returns a non-empty `failed` array. This means file-system operations (rename or unlink) on the `.wal`/`.shadow`/`.lock` sidecars failed after all retries.

Common situations: Another process (a lingering MCP server, IDE extension, or a second `gitnexus serve`) holds a handle on the sidecar files; Windows antivirus or delete-pending handle-release lag; a read-only or permission-restricted `.gitnexus` directory; NFS or network filesystem locking issues.

Related errors


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