vercel / vercel/nft

Handle broken symlinks gracefully during file tracing

Open
#601 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
1.7k
Forks
185
PR merge metrics
No merged PRs in 30d

Description

Bug Description

When @vercel/nft traces dependencies in an environment containing broken symlinks
(symlinks whose target does not exist), the tracing process throws an unhandled
ENOENT error and aborts entirely.

Steps to Reproduce

  1. Create a broken symlink in the system (e.g., /etc/alternatives/which.sl1.gz
    pointing to a non-existent target)
  2. Run nodeFileTrace() on an entry file whose dependency chain resolves through
    that directory (e.g., via a binary that references /usr/bin/which
    /etc/alternatives/which)
  3. The trace fails with: Error: ENOENT: no such file or directory, stat '/etc/alternatives/which.sl1.gz'

Expected Behavior

Broken symlinks should be skipped gracefully (similar to how _internalReadlink
already handles ENOENT by returning null). The trace should continue and
simply not include the broken symlink target in the output fileList.

Actual Behavior

The entire trace aborts with an unhandled ENOENT error, preventing any output
from being generated.

Environment

  • @vercel/nft version: 0.29.2
  • Node.js: 20.x
  • OS: Linux (CI container based on CentOS/Alpine with stale symlinks in
    /etc/alternatives)

Analysis

In src/fs.ts, _internalStat correctly returns null for ENOENT. However,
the realpath() method in src/node-file-trace.ts recursively resolves paths
by calling readlinkresolverealpath again. During this recursion,
when the resolved path traverses a directory that contains broken symlinks,
subsequent operations on adjacent files (like glob-based asset emission or
shared library detection) may attempt to stat those broken symlinks through
a code path that does not handle the null/ENOENT return gracefully.

Suggested Fix

Ensure that any code path that calls stat() or processes directory entries
during tracing handles broken symlinks (stat returning null) by skipping
the entry rather than propagating the error.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with src/fs.ts and src/node-file-trace.ts, following nodeFileTrace into realpath and the directory-entry paths that call stat. Compare those paths with _internalReadlink and _internalStat, then reproduce the broken-symlink scenario on Node.js. Done means tracing continues after ENOENT and the broken target is absent from fileList.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, node.js
Domain
devtools, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.