abhigyanpatwari/GitNexus · error · InvalidStoragePathError
must be an absolute, non-empty path.
Error message
${label} must be an absolute, non-empty path. What it means
validateAbsolutePath is the strict validator for absolute storage configuration paths. It throws when the labeled value is empty or not a string, producing a message like '<label> must be an absolute, non-empty path.' It is used for resolved storage roots, ownership metadata, and root configuration, where a relative path is never acceptable.
Solutions
- Convert to an absolute path before the call: path.resolve(value) (relative paths resolve against cwd, which may not be what you want — prefer path.isAbsolute check).
- Fix the env/config value to a full absolute path (e.g. export GITNEXUS_STORAGE_PATH=/var/lib/gitnexus).
- Ensure the value is actually a string; JSON configs sometimes carry null/numbers where a path is expected.
Example fix
// before
configuredStoragePath(process.env.GITNEXUS_STORAGE_PATH ?? 'storage');
// after
const p = process.env.GITNEXUS_STORAGE_PATH ?? path.join(os.homedir(), '.gitnexus-storage');
if (!path.isAbsolute(p)) throw new Error(`Storage path must be absolute: ${p}`);
configuredStoragePath(p); Defensive patterns
Strategy: validation
Validate before calling
if (typeof value !== 'string' || value.length === 0 || !path.isAbsolute(value)) {
throw new Error(`${label} must be a non-empty absolute path (got: ${JSON.stringify(value)})`);
} Type guard
const isAbsoluteNonEmptyPath = (v: unknown): v is string => typeof v === 'string' && v.length > 0 && path.isAbsolute(v);
Try / catch
try {
const p = resolved(value);
} catch (e) {
if (e instanceof InvalidStoragePathError) throw new Error(`storage config invalid: ${e.message}`);
throw e;
} Prevention
- Store absolute paths in env/config (no './' or bare names).
- Resolve config paths once at startup against an explicit base, not cwd.
- Validate with path.isAbsolute before calling any resolver API.
When it happens
Trigger: Calling resolved(), root(), or readOwnershipMetadata() with an empty string or relative path for a value labeled 'Storage path'/'Storage root' etc., e.g. GITNEXUS_STORAGE_PATH set to 'repos' instead of '/data/repos'.
Common situations: Env var GITNEXUS_STORAGE_PATH / GITNEXUS_STORAGE_ROOT set to a relative path; config file with missing/blank absolute path field; programmatic use passing cwd-relative paths assuming they'd be resolved.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- must be an absolute path.
- contains characters not allowed in a git ref
- err.message (InvalidBranchError rethrown as GitNexusRcError…
- exceeds bytes
- must be a regular file
AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-09-15).
Data as JSON: /api/errors/6c996cb625b524e1.
Report an issue: GitHub.
Appendix: source
Thrown at gitnexus/src/storage/storage-resolver.ts:185
const filesystemErrorDetail = (error: unknown): string => {
const code = (error as NodeJS.ErrnoException)?.code;
return code ? `${code}: ${(error as Error)?.message ?? String(error)}` : String(error);
};
const resolveRepoPath = (value: string): string => {
if (typeof value !== 'string' || value.length === 0) {
throw new InvalidStoragePathError('Repository path must be non-empty.');
}
if (value.includes('\0')) {
throw new InvalidStoragePathError('Repository path must not contain a NUL character.');
}
return path.resolve(value);
};
const validateAbsolutePath = (value: string, label: string): string => {
if (typeof value !== 'string' || value.length === 0) {
throw new InvalidStoragePathError(`${label} must be an absolute, non-empty path.`);
}
if (value.includes('\0')) {
throw new InvalidStoragePathError(`${label} must not contain a NUL character.`);
}
if (!path.isAbsolute(value)) {
throw new InvalidStoragePathError(`${label} must be an absolute path.`);
}
return path.resolve(value);
};
// Mirror registry lookup semantics without importing repo-manager and creating a cycle.
const canonicalRegistryPath = (value: string): string => {
const resolved = path.resolve(value);
try {
return stripWindowsLongPathPrefix(fs.realpathSync.native(resolved));
} catch {
return stripWindowsLongPathPrefix(resolved);
}View on GitHub (pinned to ac9a4e9abd)