abhigyanpatwari/GitNexus · error
Analyzer package lock symbolic link does not resolve to a fi
Error message
Analyzer package lock symbolic link does not resolve to a file: ${candidate} What it means
When a candidate package-lock.json is a symbolic link, findNearestPackageLock stats the target and requires it to be a regular file; if the target is a directory (or otherwise not a file) this inner branch throws. A lockfile link pointing at a directory cannot be hashed as a lockfile, and silently skipping it would drop dependency-freeze state from the receipt, so the condition is fatal rather than ignored.
Source
Thrown at gitnexus/src/core/analyzer-identity.ts:965
ancestors += 1;
if (ancestors > limits.resolutionAncestors) {
throw new Error(
`Analyzer package-lock lookup exceeded ${limits.resolutionAncestors} ancestors: ${packageRoot}`,
);
}
const candidate = path.join(cursor, 'package-lock.json');
recordDependencyPathGuard(pathGuards, candidate);
// Preserve the link path so ReadableFileState guards both the link and its
// resolved target. Realpathing here would miss a later retarget while the
// old target remained unchanged.
try {
const link = lstatSync(candidate);
if (link.isFile()) return path.resolve(candidate);
if (link.isSymbolicLink()) {
try {
const target = statSync(candidate);
if (!target.isFile()) {
throw new Error(
`Analyzer package lock symbolic link does not resolve to a file: ${candidate}`,
);
}
} catch {
throw new Error(
`Analyzer package lock symbolic link does not resolve to a file: ${candidate}`,
);
}
return path.resolve(candidate);
}
throw new Error(`Analyzer package lock is not a regular file: ${candidate}`);
} catch (error) {
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
}
const parent = path.dirname(cursor);
if (parent === cursor) return null;
cursor = parent;
}View on GitHub (pinned to aac7515d2a)
Solutions
- Point the link at an actual lockfile file: 'ln -sfn /path/to/shared/package-lock.json package-lock.json'.
- Or replace the link with a real copy of the lockfile.
- Remove stray directory links named package-lock.json from ancestor directories of the gitnexus install.
Example fix
# before: link points at a directory $ ln -sfn ../shared-locks package-lock.json # after: link points at the lockfile itself $ ln -sfn ../shared-locks/package-lock.json package-lock.json
Defensive patterns
Strategy: validation
Validate before calling
import { lstatSync, statSync } from 'node:fs';
function lockfileLinksResolveToFiles(packageRoot: string): boolean {
let cursor = packageRoot;
while (true) {
const candidate = `${cursor}/package-lock.json`;
try {
const link = lstatSync(candidate);
if (link.isFile()) return true;
if (link.isSymbolicLink()) return statSync(candidate).isFile();
return false;
} catch {
/* ENOENT: keep walking ancestors */
}
const parent = path.dirname(cursor);
if (parent === cursor) return true;
cursor = parent;
}
} Type guard
function isLockfileSymlinkTargetError(error: unknown): boolean {
return error instanceof Error && /^Analyzer package lock symbolic link does not resolve to a file:/.test(error.message);
} Try / catch
try {
identity = resolveAnalyzerRunnerIdentity(import.meta.url);
} catch (error) {
if (isLockfileSymlinkTargetError(error)) {
reportUserError(`Lockfile link points at a directory: ${error.message}; point it at the lockfile file or remove it.`);
}
throw error;
} Prevention
- When sharing lockfiles via symlinks, always link to the file, never its parent directory.
- Test provisioning scripts with readlink + stat before shipping environments that run gitnexus.
When it happens
Trigger: package-lock.json symlinked to a directory — e.g. a dotfiles/config manager that links 'package-lock.json -> ../shared/' by mistake, or a setup script that linked the lockfile to a folder containing lockfiles instead of to one lockfile file. Hit during any resolveAnalyzerRunnerIdentity call that walks ancestors from the package root.
Common situations: Shared-lockfile monorepo setups done with symlinks; Nix/conda-style environments where lockfiles are links into a store and the store path is a directory; typo'd 'ln -s' targets.
Related errors
- Analyzer package lock is not a regular file: ${candidate}
- Analyzer identity input changed while it was being read: ${c
- Analyzer runtime scan exceeded ${maxBytes} bytes: ${candidat
- Analyzer identity input changed while it was being hashed: $
- Unsupported analyzer build entry: ${absolutePath}
AI-assisted analysis of abhigyanpatwari/GitNexus@aac7515d2a (2026-08-20).
Data as JSON: /api/errors/f8efe585484d94c8.
Report an issue: GitHub.