abhigyanpatwari/GitNexus · error · Error

Analyzer build symbolic links are not supported; materialize

Error message

Analyzer build symbolic links are not supported; materialize the build tree: ${entry.absolutePath}

What it means

The build-tree receipt hashes real file content, but Node resolves imports through symlinks, so a symlink's target bytes outside buildRoot could change analyzer behaviour without changing anything the receipt covered (target containment, cycles, TOCTOU are all unsolved at that boundary). Rather than invent an incomplete trust model, the scan rejects any symbolic link inside the build tree and asks for a materialized (fully copied) tree.

Source

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

      SHA256_PATTERN.test(cached.digest) &&
      isDeepStrictEqual(cached.state, entry.state)
    ) {
      digest = cached.digest;
    } else if (entry.kind === 'file') {
      const stable = hashStableFile(entry.absolutePath);
      entry.state = stable.state.link;
      digest = stable.digest;
      options.onHashedInput?.({
        kind: 'build',
        path: entry.absolutePath,
        bytes: stable.bytes,
      });
    } else if (entry.kind === 'symlink') {
      // Imported files and directories are resolved through symlinks by Node.
      // Hashing only link text would let bytes outside buildRoot change without
      // changing the receipt. Reject them instead of inventing an incomplete
      // recursive trust boundary (target containment, cycles, and TOCTOU).
      throw new Error(
        `Analyzer build symbolic links are not supported; materialize the build tree: ${entry.absolutePath}`,
      );
    }

    updateCanonicalFrame(hash, [
      'build-entry',
      entry.relativePath,
      entry.kind,
      digest ? digestBytes(digest) : Buffer.alloc(0),
    ]);
    nextEntries.push({
      relativePath: entry.relativePath,
      kind: entry.kind,
      state: entry.state,
      ...(digest ? { digest } : {}),
    });
  }

View on GitHub (pinned to aac7515d2a)

Solutions

  1. Replace the link with a real copy: 'cp -Lr <link> <real-dir> && rm <link>' (materialize the tree).
  2. Configure the package manager to hoist/materialize instead of linking the gitnexus install (e.g. pnpm node-linker=hoisted for this dependency).
  3. Run gitnexus from a plain npm-style install where dist/ is real files.
  4. Change build tooling so post-build symlinking of dist subdirectories never runs in environments that execute analyze.

Example fix

# before: dist/vendor-grammars -> ../../shared-grammars (symlink)
$ ls -l dist/vendor-grammars
lrwxrwxrwx dist/vendor-grammars -> ../../shared-grammars

# after: materialize the tree
$ rm dist/vendor-grammars && cp -r ../../shared-grammars dist/vendor-grammars
Defensive patterns

Strategy: validation

Validate before calling

import { lstatSync, readdirSync } from 'node:fs';

function buildTreeHasNoSymlinks(buildRoot: string): boolean {
  const stack = [buildRoot];
  while (stack.length > 0) {
    const dir = stack.pop()!;
    for (const entry of readdirSync(dir, { withFileTypes: true })) {
      if (entry.isSymbolicLink()) return false;
      if (entry.isDirectory()) stack.push(`${dir}/${entry.name}`);
    }
  }
  return true;
}

Type guard

function isBuildSymlinkError(error: unknown): boolean {
  return error instanceof Error && /^Analyzer build symbolic links are not supported/.test(error.message);
}

Try / catch

try {
  identity = resolveAnalyzerRunnerIdentity(import.meta.url);
} catch (error) {
  if (isBuildSymlinkError(error)) {
    reportUserError('Materialize the build tree: replace links inside dist with real copies (cp -Lr).');
  }
  throw error;
}

Prevention

When it happens

Trigger: Any entry classified as a symlink during collectBuildEntries/hashing — typically a pnpm-style or workspace install where parts of dist/ are links into a shared store, a developer manually symlinking a subdirectory (dist/vendor -> ../../shared), or a monorepo linking gitnexus's dist to a central location while running analyze against the link path.

Common situations: pnpm workspaces or custom linkers exposing the analyzer build through symlinks; developers symlinking shared grammars or vendored modules into dist; Docker volume or deploy tooling replacing directories with links.

Related errors


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