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
- 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).
- Re-register/re-analyze the repo so the registry row is rewritten correctly: node .gitnexus/run.cjs analyze --index-only.
- 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
- Treat .gitnexus registry files as machine-managed; never hand-edit.
- Omit storagePath entirely (not null/0) when unknown so the default fallback applies.
- Validate registry JSON shape after any custom tooling writes to it.
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
- entry does not identify a repo — name and storagePath must…
- Refusing to delete storage
- Analysis did not finalize for
- Analysis not finalized: missing
- Analysis not finalized: missing registry-entry for
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)