Skip to content

Commit 7b29458

Browse files
committed
module: add requireStack to all error paths
Previously, `requireStack` was only set on the final fallback error in `Module._resolveFilename`. Errors thrown earlier in the resolution pipeline β€” from `tryPackage` (via `Module._findPath`) when a `package.json` `main` field points to a missing file, from `trySelf` during self-referential package resolution, and from `createEsmNotFoundErr` β€” did not include `requireStack`. Fix this by building `requireStack` from the parent chain before any resolution attempt and propagating it to all `MODULE_NOT_FOUND` error paths: - Wrap `trySelf` and `Module._findPath` calls in try-catch blocks that attach `requireStack` to any thrown `MODULE_NOT_FOUND` error that does not already have one. - Add an optional `requireStack` parameter to `createEsmNotFoundErr` and pass it from `_resolveFilename` where the error is thrown directly.
1 parent 6964b53 commit 7b29458

File tree

3 files changed

+35
-14
lines changed

3 files changed

+35
-14
lines changed

β€Žlib/internal/modules/cjs/loader.jsβ€Ž

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,6 @@ function tryPackage(requestPath, exts, isMain, originalPath) {
534534
err.code = 'MODULE_NOT_FOUND';
535535
err.path = pjsonPath;
536536
err.requestPath = originalPath;
537-
// TODO(BridgeAR): Add the requireStack as well.
538537
throw err;
539538
} else {
540539
process.emitWarning(
@@ -1406,6 +1405,14 @@ Module._resolveFilename = function(request, parent, isMain, options) {
14061405
paths = Module._resolveLookupPaths(request, parent);
14071406
}
14081407

1408+
const requireStack = [];
1409+
for (let cursor = parent;
1410+
cursor;
1411+
// TODO(joyeecheung): it makes more sense to use kLastModuleParent here.
1412+
cursor = cursor[kFirstModuleParent]) {
1413+
ArrayPrototypePush(requireStack, cursor.filename || cursor.id);
1414+
}
1415+
14091416
if (request[0] === '#' && (parent?.filename || parent?.id === '<repl>')) {
14101417
const parentPath = parent?.filename ?? process.cwd() + path.sep;
14111418
const pkg = packageJsonReader.getNearestParentPackageJSON(parentPath);
@@ -1419,7 +1426,7 @@ Module._resolveFilename = function(request, parent, isMain, options) {
14191426
);
14201427
} catch (e) {
14211428
if (e.code === 'ERR_MODULE_NOT_FOUND') {
1422-
throw createEsmNotFoundErr(request);
1429+
throw createEsmNotFoundErr(request, undefined, requireStack);
14231430
}
14241431
throw e;
14251432
}
@@ -1428,7 +1435,15 @@ Module._resolveFilename = function(request, parent, isMain, options) {
14281435

14291436
// Try module self resolution first
14301437
const parentPath = trySelfParentPath(parent);
1431-
const selfResolved = trySelf(parentPath, request, conditions);
1438+
let selfResolved;
1439+
try {
1440+
selfResolved = trySelf(parentPath, request, conditions);
1441+
} catch (e) {
1442+
if (e.code === 'MODULE_NOT_FOUND' && e.requireStack === undefined) {
1443+
e.requireStack = requireStack;
1444+
}
1445+
throw e;
1446+
}
14321447
if (selfResolved) {
14331448
const cacheKey = request + '\x00' +
14341449
(paths.length === 1 ? paths[0] : ArrayPrototypeJoin(paths, '\x00'));
@@ -1437,15 +1452,16 @@ Module._resolveFilename = function(request, parent, isMain, options) {
14371452
}
14381453

14391454
// Look up the filename first, since that's the cache key.
1440-
const filename = Module._findPath(request, paths, isMain, conditions);
1441-
if (filename) { return filename; }
1442-
const requireStack = [];
1443-
for (let cursor = parent;
1444-
cursor;
1445-
// TODO(joyeecheung): it makes more sense to use kLastModuleParent here.
1446-
cursor = cursor[kFirstModuleParent]) {
1447-
ArrayPrototypePush(requireStack, cursor.filename || cursor.id);
1455+
let filename;
1456+
try {
1457+
filename = Module._findPath(request, paths, isMain, conditions);
1458+
} catch (e) {
1459+
if (e.code === 'MODULE_NOT_FOUND' && e.requireStack === undefined) {
1460+
e.requireStack = requireStack;
1461+
}
1462+
throw e;
14481463
}
1464+
if (filename) { return filename; }
14491465
let message = `Cannot find module '${request}'`;
14501466
if (requireStack.length > 0) {
14511467
message = message + '\nRequire stack:\n- ' +
@@ -1485,16 +1501,19 @@ function finalizeEsmResolution(resolved, parentPath, pkgPath) {
14851501
* Creates an error object for when a requested ES module cannot be found.
14861502
* @param {string} request The name of the requested module
14871503
* @param {string} [path] The path to the requested module
1504+
* @param {string[]} [requireStack] The require stack at the time of the error
14881505
* @returns {Error}
14891506
*/
1490-
function createEsmNotFoundErr(request, path) {
1507+
function createEsmNotFoundErr(request, path, requireStack) {
14911508
// eslint-disable-next-line no-restricted-syntax
14921509
const err = new Error(`Cannot find module '${request}'`);
14931510
err.code = 'MODULE_NOT_FOUND';
14941511
if (path) {
14951512
err.path = path;
14961513
}
1497-
// TODO(BridgeAR): Add the requireStack as well.
1514+
if (requireStack) {
1515+
err.requireStack = requireStack;
1516+
}
14981517
return err;
14991518
}
15001519

β€Žtest/parallel/test-module-loading-error.jsβ€Ž

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ assert.throws(
9191
() => { require('../fixtures/packages/is-dir'); },
9292
common.isAIX ? { code: 'ERR_INVALID_PACKAGE_CONFIG' } : {
9393
code: 'MODULE_NOT_FOUND',
94-
message: /Cannot find module '\.\.\/fixtures\/packages\/is-dir'/
94+
message: /Cannot find module '\.\.\/fixtures\/packages\/is-dir'/,
95+
requireStack: [__filename],
9596
}
9697
);

β€Žtest/sequential/test-module-loading.jsβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ assert.throws(
123123
message: /packages[/\\]missing-main-no-index[/\\]doesnotexist\.js'\. Please.+package\.json.+valid "main"/,
124124
path: /fixtures[/\\]packages[/\\]missing-main-no-index[/\\]package\.json/,
125125
requestPath: /^\.\.[/\\]fixtures[/\\]packages[/\\]missing-main-no-index$/,
126+
requireStack: [__filename],
126127
}
127128
);
128129

0 commit comments

Comments
Β (0)