Skip to content

module: add requireStack to ESM exports resolution errors#62417

Open
AKXtreme wants to merge 1 commit intonodejs:mainfrom
AKXtreme:fix-esm-not-found-require-stack
Open

module: add requireStack to ESM exports resolution errors#62417
AKXtreme wants to merge 1 commit intonodejs:mainfrom
AKXtreme:fix-esm-not-found-require-stack

Conversation

@AKXtreme
Copy link

Summary

When require() fails via the ESM exports resolution path (e.g. require('pkg/subpath') where pkg has a package.json exports field), the thrown MODULE_NOT_FOUND error was missing the requireStack property and the "Require stack:" section in the message — even though the CJS resolution path has included this information for years.

This was acknowledged in a TODO(BridgeAR) comment in lib/internal/modules/cjs/loader.js.

Changes

  • createEsmNotFoundErr — accepts an optional parent Module and builds requireStack + message using the same pattern as the CJS path. Removes the TODO comment.
  • finalizeEsmResolution — threads parent through to createEsmNotFoundErr.
  • resolveExports — threads parent through. Covers the most common case: require('pkg/subpath') with an exports field.
  • Module._findPath — accepts optional 5th arg parent (fully backward-compatible) and passes it to resolveExports.
  • trySelf — threads parent through. Covers self-referencing packages.
  • Module._resolveFilename — passes parent at all three ESM call sites.

Before

Error: Cannot find module 'my-pkg/missing'

After

Error: Cannot find module 'my-pkg/missing'
Require stack:
- /app/src/utils.js
- /app/src/index.js

Test plan

  • Added test/fixtures/node_modules/pkgexports-esm-require-stack/ — a fixture package whose exports map points to a non-existent file.
  • Added test/parallel/test-require-esm-not-found-require-stack.js with two scenarios:
    • Single-level: verifies err.requireStack is present and err.message includes "Require stack:".
    • Multi-level: verifies the full caller chain appears in requireStack in the correct order (nearest caller first).

When require() fails via the ESM exports resolution path (e.g.
require('pkg/subpath') where pkg has a package.json exports field),
the thrown MODULE_NOT_FOUND error was missing the requireStack
property and the "Require stack:" section in the message that the
CJS resolution path has always included.

Thread the parent Module through createEsmNotFoundErr,
finalizeEsmResolution, resolveExports, Module._findPath, and
trySelf so all ESM resolution code paths populate requireStack
consistently with the CJS path.

Fixes TODO(BridgeAR) in lib/internal/modules/cjs/loader.js
@nodejs-github-bot
Copy link
Collaborator

Review requested:

  • @nodejs/loaders

@nodejs-github-bot nodejs-github-bot added module Issues and PRs related to the module subsystem. needs-ci PRs that need a full CI run. labels Mar 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

module Issues and PRs related to the module subsystem. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants