abhigyanpatwari/GitNexus · error · Error

Refusing to delete ${dbPath}: resolved path ${realPath} is o

Error message

Refusing to delete ${dbPath}: resolved path ${realPath} is outside storage directory

What it means

A safety guard in `ensureLbugInitialized`: when the existing `dbPath` is a directory (an old-style directory database or leftover) the code resolves the real path via `realpath` and refuses to recursively delete it unless the resolved path is inside the storage (parent) directory. This prevents a symlink or bind-mount that points the db path OUTSIDE the storage directory from causing `fs.rm({recursive:true})` to wipe an unrelated directory tree. Symlinks themselves are just unlinked (never followed).

Source

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

    conn = usable.conn;
    currentDbReadOnly = true;
  } else {
    // LadybugDB stores the database as a single file (not a directory).
    // If the path already exists, it must be a valid LadybugDB database file.
    // Remove stale empty directories or files from older versions.
    try {
      const stat = await fs.lstat(dbPath);
      if (stat.isSymbolicLink()) {
        // Never follow symlinks — just remove the link itself
        await fs.unlink(dbPath);
      } else if (stat.isDirectory()) {
        // Verify path is within expected storage directory before deleting
        const realPath = await fs.realpath(dbPath);
        const parentDir = path.dirname(dbPath);
        const realParent = await fs.realpath(parentDir);
        const safePrefix = realParent.endsWith(path.sep) ? realParent : realParent + path.sep;
        if (!realPath.startsWith(safePrefix) && realPath !== realParent) {
          throw new Error(
            `Refusing to delete ${dbPath}: resolved path ${realPath} is outside storage directory`,
          );
        }
        // Old-style directory database or empty leftover - remove it
        await fs.rm(dbPath, { recursive: true, force: true });
      }
      // If it's a file, assume it's an existing LadybugDB database - LadybugDB will open it
    } catch (err) {
      if (!isMissingFileError(err)) {
        throw err;
      }
      // Path doesn't exist, which is what LadybugDB wants for a new database
    }

    // -------------------------------------------------------------------------
    // Cross-process critical section: acquire init lock, clean orphan sidecars,
    // and open the database. The lock prevents a TOCTOU race where another
    // process could create a fresh DB between our access() check and the

View on GitHub (pinned to d540b00184)

Solutions

  1. Remove the symlink/bind-mount so `dbPath` resolves inside the storage directory, then retry.
  2. Manually delete the old directory database at its real location if it is genuinely stale, then let gitnexus create a fresh file-based DB.
  3. Do not point the dbPath at a location outside the `.gitnexus/` storage directory.
Defensive patterns

Strategy: validation

Validate before calling

import { realpathSync, lstatSync } from 'node:fs';
import path from 'node:path';

function assertDbPathInStorage(dbPath, storageDir) {
  const st = lstatSync(dbPath);
  if (st.isDirectory()) {
    const real = realpathSync(dbPath);
    const realParent = realpathSync(path.dirname(dbPath));
    const safePrefix = realParent.endsWith(path.sep) ? realParent : realParent + path.sep;
    if (!real.startsWith(safePrefix) && real !== realParent) {
      throw new Error(`dbPath resolves outside storage dir; refusing to let gitnexus delete it.`);
    }
  }
}
assertDbPathInStorage(dbPath, storageDir);

Try / catch

try {
  await initLbug(dbPath);
} catch (err) {
  if (/resolved path .* is outside storage directory/i.test(err.message)) {
    // A symlink/bind-mount points the db outside .gitnexus — remove it and retry.
    console.error(err.message);
    process.exit(9);
  }
  throw err;
}

Prevention

When it happens

Trigger: `dbPath` exists, is a directory, and `fs.realpath(dbPath)` resolves to a location whose `realPath` is neither inside `realParent` nor equal to it — e.g. a symlink-to-directory or bind-mount pointing outside `.gitnexus/`. The guard throws rather than delete.

Common situations: A user symlinked the database path to another volume/dir; a bind-mount or container volume maps the db path outside the storage tree; an old directory-style database that was relocated.

Related errors


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