Summary
When a dependency's exports-resolved entry file is missing on disk (e.g. a package manager left a package directory in a torn state: package.json from one version, dist/ from another), nodeFileTrace:
- records a
Failed to resolve dependency warning in result.warnings (good), but
- still emits the package's
package.json alone into fileList, with no entry file and no marker of the failure.
Deploying that file set produces a delayed, misleading runtime failure: Node finds the package.json, resolves its exports map, and crashes with Cannot find module '<pkg>/dist/…' — a deep internal path that implicates the package rather than the trace/install. If nft emitted nothing for the package, the runtime error would at least be the legible Cannot find module '<pkg>'.
Reproduction (self-contained)
mkdir nft-torn-repro && cd nft-torn-repro
npm init -y >/dev/null
npm i lru-cache@11.5.1 @vercel/nft@1.10.2 >/dev/null
echo "const { LRUCache } = require('lru-cache'); console.log('ok');" > entry.js
# Simulate the torn install state: the exports target for require+node
# conditions ("./dist/commonjs/node/index.min.js") is missing on disk.
rm node_modules/lru-cache/dist/commonjs/node/index.min.js
node -e "
const { nodeFileTrace } = require('@vercel/nft');
nodeFileTrace(['entry.js'], { base: process.cwd() }).then(r => {
console.log('fileList:', [...r.fileList].filter(f => f.includes('lru-cache')));
console.log('warnings:', [...r.warnings].map(w => w.message.split('\n')[0]));
});
"
Output (nft 1.10.2, Node 22):
fileList: [ 'node_modules/lru-cache/package.json' ]
warnings: [ 'Failed to resolve dependency "lru-cache":' ]
Copy fileList to a deploy target and run entry.js there:
Error: Cannot find module '/var/task/node_modules/lru-cache/dist/commonjs/node/index.min.js'
Note the warning's full message already contains that exact path — the diagnostic exists at trace time, but nothing in the emitted file set reflects it.
Real-world impact
This is not hypothetical: we traced a production 500 on a Vercel serverless function to exactly this artifact shape — the deployed function filesystem contained lru-cache's 11.x package.json but not the file its exports map resolves to, and every SSR request to the affected route failed with the deep MODULE_NOT_FOUND above, via a serverExternalPackages runtime require() chain (jsdom → cssstyle → @asamuzakjp/css-color → lru-cache). The build had succeeded with a green log (the consumer pipeline does not surface result.warnings). Diagnosing it took build-log forensics plus local reconstruction of the file-set shape; a visible trace-time diagnostic would have answered it immediately.
There is also a fully self-contained Next.js-level reproduction (green next build, zero warnings, deployed standalone output 500s / silently drops page metadata): https://github.com/linyiru/next-silent-tracing-failure
Suggestions (any subset would help)
- When exports resolution fails because the target file does not exist, don't emit the bare
package.json for that package (or tag it in the result), so the shipped artifact fails legibly instead of pointing at the package's internals.
- Offer an opt-in strict mode (e.g.
throwOnResolveError) so CI/builders can hard-fail on this class of trace failure.
- At minimum, document that
fileList may contain package.json-only entries for packages whose resolution failed, and that consumers should surface result.warnings — the major consumers (Next.js output file tracing, the Vercel builder) currently swallow them.
Environment: @vercel/nft 1.10.2, Node.js 22.22, macOS/Linux (reproduced on both).
Summary
When a dependency's
exports-resolved entry file is missing on disk (e.g. a package manager left a package directory in a torn state:package.jsonfrom one version,dist/from another),nodeFileTrace:Failed to resolve dependencywarning inresult.warnings(good), butpackage.jsonalone intofileList, with no entry file and no marker of the failure.Deploying that file set produces a delayed, misleading runtime failure: Node finds the
package.json, resolves itsexportsmap, and crashes withCannot find module '<pkg>/dist/…'— a deep internal path that implicates the package rather than the trace/install. If nft emitted nothing for the package, the runtime error would at least be the legibleCannot find module '<pkg>'.Reproduction (self-contained)
Output (nft 1.10.2, Node 22):
Copy
fileListto a deploy target and runentry.jsthere:Note the warning's full message already contains that exact path — the diagnostic exists at trace time, but nothing in the emitted file set reflects it.
Real-world impact
This is not hypothetical: we traced a production 500 on a Vercel serverless function to exactly this artifact shape — the deployed function filesystem contained
lru-cache's 11.xpackage.jsonbut not the file itsexportsmap resolves to, and every SSR request to the affected route failed with the deepMODULE_NOT_FOUNDabove, via aserverExternalPackagesruntimerequire()chain (jsdom → cssstyle → @asamuzakjp/css-color → lru-cache). The build had succeeded with a green log (the consumer pipeline does not surfaceresult.warnings). Diagnosing it took build-log forensics plus local reconstruction of the file-set shape; a visible trace-time diagnostic would have answered it immediately.There is also a fully self-contained Next.js-level reproduction (green
next build, zero warnings, deployed standalone output 500s / silently drops page metadata): https://github.com/linyiru/next-silent-tracing-failureSuggestions (any subset would help)
package.jsonfor that package (or tag it in the result), so the shipped artifact fails legibly instead of pointing at the package's internals.throwOnResolveError) so CI/builders can hard-fail on this class of trace failure.fileListmay containpackage.json-only entries for packages whose resolution failed, and that consumers should surfaceresult.warnings— the major consumers (Next.js output file tracing, the Vercel builder) currently swallow them.Environment:
@vercel/nft1.10.2, Node.js 22.22, macOS/Linux (reproduced on both).