abhigyanpatwari/GitNexus · error · LbugWipeError
Failed to remove the LadybugDB index files — still present…
Error message
Failed to remove the LadybugDB index files — still present after 5 attempts:
${survivors.map((p) => ` - ${p}`).join('\n')}
The blocking handle may be another process, a lingering handle from this process's just-closed database, or an antivirus scan — an immediate re-run often succeeds. If it persists, stop any GitNexus MCP or serve process using this repository, add an antivirus exclusion for the GitNexus storage directory, then re-run the analyze. What it means
LbugWipeError from wipeLbugDbFiles (gitnexus/src/core/lbug/lbug-adapter.ts:2383). A full-rebuild wipe rm-probes each member of the 4-file family (<db>, .wal, .shadow, .lock) and counts it gone only on ENOENT. After HANDLE_RELEASE_PROBE_ATTEMPTS (5) retries, data-bearing survivors — everything except the contentless .lock, which is tolerated with a warning — fail the rebuild, because reopening would resurrect rows the run believes it wiped.
Solutions
- Immediately re-run the analyze — transient handle-release lag often clears on its own
- Stop every GitNexus MCP or serve process using this repository, then re-run
- Add an antivirus exclusion for the GitNexus storage directory
- On POSIX, confirm no holder remains: lsof +D <storage-dir>, kill the listed PIDs, re-run
Defensive patterns
Strategy: retry
Validate before calling
// before a forced rebuild, confirm nothing holds the index family open (POSIX)
import { execFile } from 'node:child_process';
const holders = await new Promise<string>((res) =>
execFile('lsof', ['-t', dbPath, `${dbPath}.wal`, `${dbPath}.shadow`],
(_e, stdout) => res(stdout.toString().trim())),
);
if (holders) throw new Error(`index still held by PIDs: ${holders}`); Type guard
import { LbugWipeError } from '../core/lbug/lbug-adapter.js';
const isLbugWipeError = (e: unknown): e is LbugWipeError => e instanceof LbugWipeError; Try / catch
try {
await wipeLbugDbFiles(dbPath);
} catch (e) {
if (isLbugWipeError(e)) {
// transient handle lag — stop holders, then retry the wipe once before failing
await stopGitNexusServeProcesses();
await retryOnce(() => wipeLbugDbFiles(dbPath));
}
throw e;
} Prevention
- Stop `gitnexus serve` and MCP sessions before any forced full rebuild
- Add an antivirus exclusion for the GitNexus storage directory on Windows hosts
- Treat a wipe failure as retryable-once — handle-release lag usually clears in seconds
When it happens
Trigger: gitnexus analyze --force (or the #2409 escalation wipe) while another GitNexus MCP/serve process still holds the database files open; Windows delete-pending handle-release lag; an antivirus scan holding handles on the storage directory.
Common situations: Forgetting to stop `gitnexus serve` or an MCP session before a forced rebuild on Windows; on-access AV scanners touching the storage dir mid-wipe; a just-closed database in the same process whose handles have not been released yet.
Related errors
- GitNexus could not move the LadybugDB WAL sidecar at
- : branch name must not contain whitespace.
- GitNexus could not move the LadybugDB WAL sidecar at
- GitNexus: failed to reclaim missing-shadow WAL quarantines
- GitNexus: failed to release init lock
AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-08-20).
Data as JSON: /api/errors/fbb3cdba3366cad3.
Report an issue: GitHub.
Appendix: source
Thrown at gitnexus/src/core/lbug/lbug-adapter.ts:2495
if (!gone) survivors.push(f);
}
if (survivors.length === 0) return;
if (attempt < HANDLE_RELEASE_PROBE_ATTEMPTS) {
await sleep(HANDLE_RELEASE_PROBE_DELAY_MS * attempt);
}
}
// Class split (FIX 2): the contentless `.lock` never fails the wipe.
const dataSurvivors = survivors.filter((f) => f !== lockPath);
if (survivors.includes(lockPath)) {
logger.warn(
`GitNexus: ${lockPath} is still present after the wipe retries — continuing: the ` +
'lock file is contentless and initLbug recreates it; a genuinely held lock will ' +
"surface as the reopen's own lock-busy error.",
);
}
if (dataSurvivors.length > 0) {
throw new LbugWipeError(dataSurvivors);
}
};
export const isLbugReady = (): boolean => conn !== null && db !== null;
/**
* Multi-label alternation over exactly the labels that can own embedding
* rows: EMBEDDABLE_LABELS plus File, which embedding-pipeline.ts embeds as
* the zero-symbol fallback for text-only repositories (#2454). Reserved
* keywords are backtick-escaped via {@link escapeTableName}. Probed on
* @ladybugdb/core 0.18.0 (this shipping review, FIX 4): the full multi-label
* alternation parses, executes, and deletes exactly the joined rows —
* replacing the unlabeled `MATCH (n)` that scanned EVERY node table per
* chunk (BasicBlock-dominated under `--pdg`) when only embeddable labels
* can match an embedding row. Including File is free for code repositories:
* they never hold File embedding rows, so the extra label joins nothing.
*/
const embeddableLabelMatch = (): string =>View on GitHub (pinned to ac9a4e9abd)