abhigyanpatwari/GitNexus · error · InvalidStoragePathError

Registered storage path for

Error message

Registered storage path for ${repoPath} must be an absolute, non-empty path.

What it means

registeredStoragePath looks up a repository's registered storagePath from the mirror registry. If the row carries a storagePath that is not a string (corrupted type, wrong JSON type), it throws InvalidStoragePathError 'Registered storage path for <repoPath> must be an absolute, non-empty path.' Note that rows with storagePath === undefined intentionally fall through to the repo-local default and do NOT throw.

Solutions

  1. Inspect the registry row for that repoPath and fix storagePath to a proper absolute-path string (or delete the field so it falls back to the repo-local default).
  2. Re-register/re-analyze the repo so the registry row is rewritten correctly: node .gitnexus/run.cjs analyze --index-only.
  3. Harden any custom writers so they serialize storagePath as a string and omit it entirely when unknown.

Example fix

// before
{ "repoPath": "/work/app", "storagePath": 0 }
// after
{ "repoPath": "/work/app", "storagePath": "/var/lib/gitnexus-storage/app-a1b2c3" }
Defensive patterns

Strategy: type-guard

Validate before calling

const row = readRegistryRow(repoPath);
if (row.storagePath !== undefined && typeof row.storagePath !== 'string') {
  console.warn(`registry storagePath for ${repoPath} has wrong type (${typeof row.storagePath}); fixing row`);
  delete row.storagePath; // fall back to repo-local default
}

Type guard

const hasValidStoragePath = (row: { storagePath?: unknown }): row is { storagePath?: string } =>
  row.storagePath === undefined || (typeof row.storagePath === 'string' && row.storagePath.length > 0);

Try / catch

try {
  const p = registered(repoPath);
} catch (e) {
  if (e instanceof InvalidStoragePathError && e.message.includes('Registered storage path')) {
    throw new Error(`registry row for ${repoPath} is corrupt; re-run analyze to rewrite it`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling registered() for a repo whose registry row has storagePath set to null, a number, boolean, or object — e.g. a hand-edited registry file, a writer bug storing the wrong type, or a partial migration writing placeholder values.

Common situations: Manual edits to the registry/index files; a failed write truncating or corrupting the registry JSON; older tooling or scripts inserting placeholder values like 0 or false into storagePath.

Related errors


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

Appendix: source

Thrown at gitnexus/src/storage/storage-resolver.ts:317

    if (!Array.isArray(data)) return undefined;
    entries = data;
  } catch {
    return undefined;
  }

  const resolvedRepoPath = canonicalRegistryPath(repoPath);
  for (const entry of entries) {
    if (entry === null || typeof entry !== 'object' || Array.isArray(entry)) continue;
    const registryEntry = entry as RegistryStorageEntry;
    if (typeof registryEntry.path !== 'string') continue;
    if (!samePath(canonicalRegistryPath(registryEntry.path), resolvedRepoPath)) continue;
    if (registryEntry.storagePath === undefined) {
      // Pre-external-storage rows have no storagePath. Match readRegistry():
      // fall through to the repository-local default instead of failing closed.
      return undefined;
    }
    if (typeof registryEntry.storagePath !== 'string') {
      throw new InvalidStoragePathError(
        `Registered storage path for ${repoPath} must be an absolute, non-empty path.`,
      );
    }
    return validateConfiguredStoragePath(registryEntry.storagePath);
  }
  return undefined;
};

/** Resolve one repository's complete index directory. */
export const resolveStoragePath = (repoPath: string): string => {
  const resolvedRepoPath = resolveRepoPath(repoPath);
  const configuredPath = configuredStoragePath();
  if (configuredPath) return configuredPath;

  const configuredRoot = configuredStorageRoot(resolvedRepoPath);
  if (configuredRoot) return configuredRoot;

  const registered = registeredStoragePath(resolvedRepoPath);

View on GitHub (pinned to ac9a4e9abd)