abhigyanpatwari/GitNexus · error · FtsReaderUnrepairableError
FTS_READER_UNREPAIRABLE
FTS_READER_UNREPAIRABLE
Error message
Cannot open ${path.basename(dbPath)} read-only after an in-place FTS abort. The leftover WAL would replay and kill this process. Run `gitnexus analyze --repair-fts` after stopping any GitNexus MCP or serve process. What it means
assertReadOnlyFtsCrashSafe refuses to open the database read-only when sidecar metadata shows an incremental FTS checkpoint was in progress with FTS capabilities and a live WAL sidecar still exists on disk. Replaying that leftover WAL in a read-only open would crash the process, so it throws FtsReaderUnrepairableError (code FTS_READER_UNREPAIRABLE) and directs the user to --repair-fts.
Solutions
- Stop any GitNexus MCP or serve process holding the database.
- Run `gitnexus analyze --repair-fts` to repair the FTS indexes and clean the leftover WAL.
- If repair fails, run `gitnexus clean --lbug-sidecars` and then re-run `gitnexus analyze`.
Defensive patterns
Strategy: validation
Validate before calling
import { inspectLbugSidecars, sidecarHasLiveWal } from 'gitnexus/...';
const state = await inspectLbugSidecars(dbPath);
if (sidecarHasLiveWal(state)) {
console.error('Leftover WAL from an FTS crash; run: gitnexus analyze --repair-fts');
} Type guard
const isFtsReaderUnrepairable = (e: unknown): e is FtsReaderUnrepairableError => e instanceof FtsReaderUnrepairableError;
Try / catch
try {
await openReadOnly(dbPath);
} catch (err) {
if (isFtsReaderUnrepairable(err)) {
console.error('Run `gitnexus analyze --repair-fts` after stopping MCP/serve processes.');
} else throw err;
} Prevention
- Avoid killing analyze processes mid-run (SIGKILL) — stop MCP/serve before forced shutdowns.
- Run `gitnexus analyze --repair-fts` promptly after any crash during FTS checkpoints.
- Ensure only one process opens the database at a time.
When it happens
Trigger: Opening the LadybugDB database read-only (e.g. by the MCP server or `gitnexus serve`) after a prior process aborted mid in-place FTS checkpoint, leaving a live .wal sidecar; inspectLbugSidecars confirms the WAL is still present.
Common situations: A crashed or SIGKILLed analyze run during an incremental FTS checkpoint; opening the repo with MCP/serve afterwards; running on a machine where the previous session terminated unexpectedly.
Related errors
- Cannot park after an in-place FTS abort )` : ''}. The…
- Cannot park after an in-place FTS abort )` : ''}. The…
- Cannot repair FTS indexes: the LadybugDB FTS extension…
- GitNexus: failed to reclaim missing-shadow WAL quarantines
- LadybugDB checkpoint sidecar is present but unreachable for
AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-09-15).
Data as JSON: /api/errors/e6a18f04d4fae637.
Report an issue: GitHub.
Appendix: source
Thrown at gitnexus/src/core/lbug/sidecar-recovery.ts:77
* abort (live dirty flag, or a persisted in-place `native-abort`) and a
* WAL is still live, refuse before the native open. Does not write,
* rename, or repair. Parking still requires the conjunctive
* `allowsFtsCrashWalPark` warrant. Missing or unreadable meta falls
* through to today's open path.
*/
export const assertReadOnlyFtsCrashSafe = async (dbPath: string): Promise<void> => {
let meta;
try {
meta = await loadMeta(path.dirname(dbPath));
} catch {
return;
}
if (!meta || !shouldRefuseFtsCrashWal(meta.incrementalInProgress, meta.capabilities?.fts)) {
return;
}
const state = await inspectLbugSidecars(dbPath);
if (!sidecarHasLiveWal(state)) return;
throw new FtsReaderUnrepairableError(dbPath);
};
export const ftsCrashParkFailureMessage = (failedPath: string, err?: unknown): string => {
const detail = err instanceof Error ? err.message : err != null ? String(err) : '';
return (
`Cannot park ${path.basename(failedPath)} after an in-place FTS abort` +
(detail ? ` (${detail})` : '') +
`. The database was not opened. Run \`${CLEAN_LBUG_SIDECARS_COMMAND}\` ` +
'after stopping any GitNexus MCP or serve process, then retry ' +
'`gitnexus analyze` or `gitnexus analyze --repair-fts`.'
);
};
/**
* Counter-based warn anti-spam (PR #1747 review, Finding 6).
*
* The previous design (`warnedKeys: Set<string>`) warned exactly once per key
* per process and silently downgraded all subsequent occurrences to debug. InView on GitHub (pinned to ac9a4e9abd)