abhigyanpatwari/GitNexus · error

Analyzer runtime payload scan exceeded ${limits.runtimePaylo

Error message

Analyzer runtime payload scan exceeded ${limits.runtimePayloads} payloads: ${root}

What it means

Thrown from the UNFOLLOWED-SYMLINK branch of collectArtifacts (the `stat.isSymbolicLink() && !isFile()` arm) when budget.artifacts crosses limits.runtimePayloads (default 100_000). This arm records symbolic links that point at non-regular-file targets (directories, dangling links, or out-of-package links) by their link text rather than by following them; the cap bounds how many such links the identity receipt will carry.

Source

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

        // for every name, not just the pruned four — `dist -> build`, a
        // vendored-grammar link, anything a sibling checkout ships.
        //
        // Such links are RECORDED by their link text rather than followed.
        // Following them would (a) recurse without cycle protection — this
        // traversal has none, so `self -> .` would ride the depth limit, which
        // THROWS, trading one hard abort for another; (b) re-scan trees already
        // reached by their real path, inflating the entry/byte budgets that
        // also throw; and (c) need a whole containment/TOCTOU trust boundary
        // for targets outside the package. Recording the text is cycle-free,
        // costs one `readlink`, and still moves the receipt when the link is
        // retargeted. The trade-off is that a link's target contributes no
        // content of its own: when it points outside the package, only the
        // link text is covered. Links that DO resolve to a regular file keep
        // their content digest below, unchanged.
        if (shouldHashRuntimePayload(relativePath)) {
          budget.artifacts += 1;
          if (budget.artifacts > limits.runtimePayloads) {
            throw new Error(
              `Analyzer runtime payload scan exceeded ${limits.runtimePayloads} payloads: ${root}`,
            );
          }
          artifacts.push({
            absolutePath,
            canonicalPath: `${canonicalPrefix}/${relativePath}`,
            kind: 'unfollowed-symlink',
          });
        }
      } else if (
        (stat.isFile() || stat.isSymbolicLink()) &&
        shouldHashRuntimePayload(relativePath)
      ) {
        const readableState = snapshotReadableFile(absolutePath);
        const payloadBytes = stateSize(readableState.target, absolutePath);
        budget.artifacts += 1;
        if (budget.artifacts > limits.runtimePayloads) {
          throw new Error(

View on GitHub (pinned to d540b00184)

Solutions

  1. Count non-file symlinks: `find <packageRoot> -type l ! -xtype f | wc -l` and identify the source directory.
  2. Reduce workspace symlinks: prefer a hoisted node_modules or `npm install --no-links` / pnpm `node-linker=hoisted` for the analyzer run.
  3. Repair dangling links: re-run the install/build that created them so they resolve, or remove them.
  4. If a build step generates the links, run the analyzer before that step or against a production install.

Example fix

// before: pnpm creates 120k cross-package directory symlinks
//   -> "Analyzer runtime payload scan exceeded 100000 payloads: /pkg"
//
// after: hoist node_modules for the analyzer invocation
//   $ pnpm install --node-linker=hoisted
//   $ node .gitnexus/run.cjs analyze --index-only
Defensive patterns

Strategy: validation

Validate before calling

const { execSync } = require('node:child_process');
function assertUnfollowedSymlinkCountFeasible(packageRoot, limit = 95_000) {
  // Count symlinks that do NOT resolve to a regular file (the 'unfollowed' arm).
  let out;
  try {
    out = execSync(
      `find . -type l ! -xtype f -not -path '*/node_modules/*' | wc -l`,
      { cwd: packageRoot, stdio: ['ignore','pipe','ignore'] }
    ).toString().trim();
  } catch { return; }
  const count = Number(out);
  if (Number.isFinite(count) && count > limit) {
    throw new Error(`Unfollowed-symlink count ${count} near the 100000 payload limit; reduce workspace links.`);
  }
}
// assertUnfollowedSymlinkCountFeasible(process.cwd());

Prevention

When it happens

Trigger: A package tree containing a very large number of directory/dangling/non-file symbolic links that are NOT pruned (i.e. not named node_modules/.git/.hg/.svn) and not resolvable to a regular file. Each such link, if shouldHashRuntimePayload(relativePath) is true, increments budget.artifacts and pushes an 'unfollowed-symlink' RuntimeArtifact; crossing 100k throws.

Common situations: A monorepo that symlink-links many sibling workspace package directories (workspace linking via `npm link` / pnpm's symlink layout) creating thousands of cross-package directory symlinks; a vendored-grammar install that ships many dangling links after a partial build; a container bind-mount presenting the build tree with many overlay symlinks.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/7e8cb788062871d0. Report an issue: GitHub.