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

  1. Point the link at an actual lockfile file: 'ln -sfn /path/to/shared/package-lock.json package-lock.json'.
  2. Or replace the link with a real copy of the lockfile.
  3. 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 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


AI-assisted analysis of abhigyanpatwari/GitNexus@aac7515d2a (2026-08-20). Data as JSON: /api/errors/f8efe585484d94c8. Report an issue: GitHub.