esm: add `ERR_REQUIRE_ESM_RACE_CONDITION` · nodejs/node@ddf1f01
@@ -27,6 +27,7 @@ const {
2727ERR_REQUIRE_ASYNC_MODULE,
2828ERR_REQUIRE_CYCLE_MODULE,
2929ERR_REQUIRE_ESM,
30+ERR_REQUIRE_ESM_RACE_CONDITION,
3031ERR_UNKNOWN_MODULE_FORMAT,
3132} = require('internal/errors').codes;
3233const { getOptionValue } = require('internal/options');
@@ -48,6 +49,7 @@ const {
4849 kEvaluating,
4950 kEvaluationPhase,
5051 kInstantiated,
52+ kUninstantiated,
5153 kErrored,
5254 kSourcePhase,
5355 throwIfPromiseRejected,
@@ -101,24 +103,6 @@ const { translators } = require('internal/modules/esm/translators');
101103const { defaultResolve } = require('internal/modules/esm/resolve');
102104const { defaultLoadSync, throwUnknownModuleFormat } = require('internal/modules/esm/load');
103105104-/**
105- * Generate message about potential race condition caused by requiring a cached module that has started
106- * async linking.
107- * @param {string} filename Filename of the module being required.
108- * @param {string|undefined} parentFilename Filename of the module calling require().
109- * @param {boolean} isForAsyncLoaderHookWorker Whether this is for the async loader hook worker.
110- * @returns {string} Error message.
111- */
112-function getRaceMessage(filename, parentFilename, isForAsyncLoaderHookWorker) {
113-let raceMessage = `Cannot require() ES Module ${filename} because it is not yet fully loaded.\n`;
114-raceMessage += 'This may be caused by a race condition if the module is simultaneously dynamically ';
115-raceMessage += 'import()-ed via Promise.all().\n';
116-raceMessage += 'Try await-ing the import() sequentially in a loop instead.\n';
117-raceMessage += ` (From ${parentFilename ? `${parentFilename} in ` : ' '}`;
118-raceMessage += `${isForAsyncLoaderHookWorker ? 'loader hook worker thread' : 'non-loader-hook thread'})`;
119-return raceMessage;
120-}
121-122106/**
123107 * @typedef {import('../cjs/loader.js').Module} CJSModule
124108 */
@@ -306,7 +290,7 @@ class ModuleLoader {
306290const parentFilename = urlToFilename(parent?.filename);
307291// This race should only be possible on the loader hook thread. See https://github.com/nodejs/node/issues/59666
308292if (!job.module) {
309-assert.fail(getRaceMessage(filename, parentFilename), this.isForAsyncLoaderHookWorker);
293+throw new ERR_REQUIRE_ESM_RACE_CONDITION(filename, parentFilename, this.isForAsyncLoaderHookWorker);
310294}
311295const status = job.module.getStatus();
312296debug('Module status', job, status);
@@ -339,8 +323,8 @@ class ModuleLoader {
339323throwIfPromiseRejected(job.instantiated);
340324}
341325if (status !== kEvaluating) {
342-assert.fail(`Unexpected module status ${status}. ` +
343- getRaceMessage(filename, parentFilename));
326+assert(status === kUninstantiated, `Unexpected module status ${status}`);
327+throw new ERR_REQUIRE_ESM_RACE_CONDITION(filename, parentFilename, false);
344328}
345329let message = `Cannot require() ES Module ${filename} in a cycle.`;
346330if (parentFilename) {
@@ -376,7 +360,7 @@ class ModuleLoader {
376360 #checkCachedJobForRequireESM(specifier, url, parentURL, job) {
377361// This race should only be possible on the loader hook thread. See https://github.com/nodejs/node/issues/59666
378362if (!job.module) {
379-assert.fail(getRaceMessage(url, parentURL, this.isForAsyncLoaderHookWorker));
363+throw new ERR_REQUIRE_ESM_RACE_CONDITION(url, parentURL, this.isForAsyncLoaderHookWorker);
380364}
381365// This module is being evaluated, which means it's imported in a previous link
382366// in a cycle.