abhigyanpatwari/GitNexus · error

LadybugDB not found at

Error message

LadybugDB not found at ${dbPath}. Run: gitnexus analyze

What it means

doInitLbug (gitnexus/src/core/lbug/pool-adapter.ts:718) stat'd the database file before opening and it is not there: the pool has no index to serve. The pool is read-only by design — only `gitnexus analyze` creates the database, so the fix is to build the index first.

Solutions

  1. Run `gitnexus analyze` on the repository to build the index, then retry
  2. Verify the resolved dbPath actually exists on disk and fix the storage/repo mapping if it points elsewhere
  3. If the index was deliberately removed, restore it from backup or re-analyze

Example fix

// before — init throws when the index was never built
await initLbug(repoId, dbPath);

// after — build the index first, then open the pool
if (!(await fs.stat(dbPath).then(() => true, () => false))) {
  await runAnalyze(repoPath); // creates the database
}
await initLbug(repoId, dbPath);
Defensive patterns

Strategy: validation

Validate before calling

// check the index exists before opening the pool
import { stat } from 'node:fs/promises';
const exists = await stat(dbPath).then(
  () => true,
  () => false,
);
if (!exists) {
  throw new Error(`no index at ${dbPath} — run gitnexus analyze first`);
}

Type guard

const isLbugNotFound = (e: unknown): boolean =>
  e instanceof Error && e.message.startsWith('LadybugDB not found at');

Try / catch

try {
  await initLbug(repoId, dbPath);
} catch (e) {
  if (isLbugNotFound(e)) {
    // build the index, then retry the open
    await runAnalyze(repoPath);
    await initLbug(repoId, dbPath);
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling initLbug(repoId, dbPath) — directly or via MCP/serve startup — for a repository that was never analyzed, whose storage directory was deleted or moved, or whose repoId-to-path mapping resolves to the wrong location.

Common situations: Fresh clone with serve started before the first analyze; storage dir wiped by a cleanup script or CI; a config or mapping regression pointing at a non-existent path.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-09-15). Data as JSON: /api/errors/6aebe54eb4e21743. Report an issue: GitHub.

Appendix: source

Thrown at gitnexus/src/core/lbug/pool-adapter.ts:803

    if (existing.checkedOut > 0) return { status: 'done', reopened: false };
    // Awaited: see the rationale on the evictLRU call site in doInitLbug below.
    await closeOne(repoId); // idle & changed → evict, then fall through to reopen the new file
  }

  return doInitLbug(repoId, dbPath);
};

/**
 * Internal init — creates DB, pre-warms connections, loads FTS, then registers pool.
 * Pool entry is registered LAST so concurrent executeQuery calls see either
 * "not initialized" (and throw) or a fully ready pool — never a half-built one.
 */
async function doInitLbug(repoId: string, dbPath: string): Promise<InitLbugAttempt> {
  // Check if database exists
  try {
    await fs.stat(dbPath);
  } catch {
    throw new Error(`LadybugDB not found at ${dbPath}. Run: gitnexus analyze`);
  }

  // Awaited: without this, the connection opened just below could race the
  // checkpoint from the LRU victim's still-in-flight close (see evictLRU /
  // closeOne). The caller holds withPoolLock for this attempt, so this await
  // only covers this call's own evict-then-reopen — not other callers.
  // Lock-retry re-enters this function after sleeping *outside* the mutex.
  // evictLRU is a no-op unless the pool is full again (another repo may have
  // taken the slot we freed on a prior attempt). Skipping it on retry would
  // let a 6th native open race a still-resident victim's checkpoint.
  await evictLRU();

  // Reuse an existing native Database if another repoId already opened this path.
  // This prevents buffer manager exhaustion from multiple mmap regions on the same file.
  let shared = dbCache.get(dbPath);
  if (shared && !shared.external && shared.dbIdentity) {
    // #2614 F2: a cached read-only Database is keyed by dbPath and shared across
    // pool consumers. If the on-disk index was rebuilt/swapped (new inode) while

View on GitHub (pinned to ac9a4e9abd)