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

  1. Stop any GitNexus MCP or serve process holding the database.
  2. Run `gitnexus analyze --repair-fts` to repair the FTS indexes and clean the leftover WAL.
  3. 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

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


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. In

View on GitHub (pinned to ac9a4e9abd)