abhigyanpatwari/GitNexus · error

Analyzer dependency resolution exceeded ${limits.resolutionA

Error message

Analyzer dependency resolution exceeded ${limits.resolutionAncestors} ancestors: ${packageName}

What it means

resolveDependencyPackageRoot() implements Node-style upward resolution: from each ancestor directory it probes <dir>/node_modules/<packageName>/package.json, counting one ancestor per level and throwing past limits.resolutionAncestors (default 256). Each lexical hop is guarded because package managers expose packages through symlinks that can be retargeted. Exceeding 256 levels means the resolution walk ran unboundedly deep, which only happens in constructed layouts.

Source

Thrown at gitnexus/src/core/analyzer-identity.ts:1119

      if (isLocallyLinkedSpecifier(specifier)) names.add(name);
    }
  }
  return [...names].sort(compareBytes);
}

function resolveDependencyPackageRoot(
  fromRoot: string,
  packageName: string,
  pathGuards: Map<string, DependencyPathGuardResult>,
  limits: AnalyzerIdentityTraversalLimits,
): string | null {
  let cursor = fromRoot;
  const segments = packageName.split('/');
  let ancestors = 0;
  while (true) {
    ancestors += 1;
    if (ancestors > limits.resolutionAncestors) {
      throw new Error(
        `Analyzer dependency resolution exceeded ${limits.resolutionAncestors} ancestors: ${packageName}`,
      );
    }
    const nodeModulesRoot = path.join(cursor, 'node_modules');
    recordDependencyPathGuard(pathGuards, nodeModulesRoot);
    let candidateParent = nodeModulesRoot;
    for (const segment of segments) {
      candidateParent = path.join(candidateParent, segment);
      // Guard every lexical hop, not only the final manifest. Package
      // managers commonly expose packages through symlinks; a retarget can
      // otherwise preserve a hard-linked manifest's stat identity while
      // changing the runtime payload tree selected by Node.
      recordDependencyPathGuard(pathGuards, candidateParent);
    }
    const manifestPath = path.join(candidateParent, 'package.json');
    recordDependencyPathGuard(pathGuards, manifestPath);
    if (isFile(manifestPath)) return resolveExistingPath(path.dirname(manifestPath));
    const parent = path.dirname(cursor);

View on GitHub (pinned to 52924ef12c)

Solutions

  1. Install/run gitnexus at a conventional path depth.
  2. Adjust test traversalLimits so resolutionAncestors exceeds the fixture's real ancestor count.
  3. Check for mount-induced loops if the depth seems normal.
Defensive patterns

Strategy: try-catch

Type guard

function isDependencyAncestorLimitError(error: unknown): boolean {
  return error instanceof Error && /^Analyzer dependency resolution exceeded \d+ ancestors:/.test(error.message);
}

Try / catch

try {
  identity = resolveAnalyzerRunnerIdentity(import.meta.url);
} catch (error) {
  if (isDependencyAncestorLimitError(error)) {
    reportUserError('Module resolution walked too many ancestors; move the install to a normal path depth.');
  }
  throw error;
}

Prevention

When it happens

Trigger: Resolving a dependency name when the package root sits deeper than 256 directory levels below the filesystem root, or when tests tighten resolutionAncestors below the fixture's actual node_modules depth. The counter increments per ancestor directory visited, not per dependency, so normal hoisting never approaches it.

Common situations: Test fixtures with small resolutionAncestors overrides; pathologically nested temp directories; filesystem loops via bind mounts.

Related errors


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