require()先のES Module、またはそのimport依存グラフにトップレベルawaitがあると、同期処理のrequire()では読み込めません。CommonJS側をimport()へ変え、返されるPromiseの完了をawaitするのが基本の修正です。
ERR_REQUIRE_ASYNC_MODULEや「require() cannot be used on an ESM graph with top-level await」は、直接の読み込み先だけでなく、その先の依存を含むESMグラフが非同期であることを示します。
同期ESMはrequireできるが、非同期ESMはできない
現在のNode.jsでは、ESMをすべてrequire()できないわけではありません。Node.jsのCommonJS modules資料では、トップレベルawaitを含まない完全に同期的なESMグラフは、条件を満たせばrequire()で読み込めると説明されています。グラフ内のどこかにトップレベルawaitがある場合は、評価完了を同期的に返せないため、このエラーになります。
同期ESMのrequire()はNode.js 20.19.0、22.12.0、23.0.0以降で既定有効です。「CommonJSからESMは一切requireできない」という古い一般論では切り分けられません。2026年10月4日時点の主な系列差は次のとおりです。
| 系列 | 本件での違い |
|---|---|
| Node 22 | 22.12.0以降で同期ESMのrequire()が既定有効。診断フラグはモジュールを評価して場所を探す |
| Node 24 | 24.15.0以降でrequire(esm)が非実験扱い。24.20.0以降には診断改善がバックポート。それ以前の診断フラグはモジュールを評価する |
| Node 26 | 26.5.0以降でrequireStackとtopLevelAwaitLocationsを追加し、診断時にモジュールを評価しない |
Node 26.5.0で追加された診断用error propertiesを、Node 22やNode 24全般にあるものとして扱ってはいけません。topLevelAwaitLocationsは診断フラグ使用時だけ設定されます。Node 24では24.20.0以降にバックポートされていますが、それ以前にはありません。バックポートはNode 24.20.0のErrors資料で確認できます。詳細はERR_REQUIRE_ASYNC_MODULEの公式説明を確認してください。
空の作業用ディレクトリで再現する
新しい空のディレクトリに次の2ファイルを作ります。.mjsはESM、.cjsはCommonJSを明示するため、package.jsonは不要です。
async.mjs
export const value = await Promise.resolve('ok');
main.cjs
const { value } = require('./async.mjs');
console.log(value);
node main.cjs
async.mjsはファイル直下でawaitしているため、同期的なrequire()では読めず、ERR_REQUIRE_ASYNC_MODULEになります。これは公式仕様に基づく最小例です。まずnode --versionで実行版を確認してください。

import()で読込完了を待つ修正
CommonJSから非同期ESMを読む場合は、import()が返すPromiseを待ちます。呼び出しとエラー処理まで含めると次の形です。
修正後のmain.cjs
async function main() {
const { value } = await import('./async.mjs');
console.log(value);
}
main().catch((error) => {
console.error('モジュールの読み込みに失敗しました');
console.error(error);
process.exitCode = 1;
});
valueはnamed exportなので分割代入できます。読み込み先がexport defaultなら、const { default: value } = await import(...)またはmodule.defaultを使います。import()はPromiseなので、awaitせずにmodule.valueを読んではいけません。
上の再現例と修正例はWindowsのNode.js v24.19.0で実行し、require()ではERR_REQUIRE_ASYNC_MODULE、import()修正後はokの出力を確認しました。
直接のファイルにawaitがなくても失敗する理由
判定対象は依存グラフ全体です。たとえばentry.mjs自身にトップレベルawaitがなくても、そこからimport './async.mjs'していれば、require('./entry.mjs')は失敗します。依存ライブラリ更新後に発生した場合は、追加・更新された依存先まで追います。
build toolやtest toolがプラグインを同期require()する設計なら、呼び出し側だけでは直せない場合があります。利用中のNode.js版と、各ツールのESM・トップレベルawait対応を公式資料で確認してください。
実プロジェクトでの切り分け順
node --versionで、ローカル、CI、コンテナの実行版を確認する- 入口の拡張子と、最寄りの
package.jsonの"type"を確認する - 失敗したstep、最初のエラー、stackから同期
require()の入口を特定する - 直接の対象から、その
import先へ依存グラフを追う - 必要なら信頼できる最小再現projectで
--experimental-print-required-tlaを使う import()への変更、依存更新、toolの互換設定を検討する
.cjsはCommonJS、.mjsはESMです。.jsは最寄りのpackage.jsonにある"type": "commonjs"または"type": "module"の影響を受けます。type指定がない場合は、対応版ではESM構文の検出も関わります。判定規則はModules: Packages公式資料を参照してください。
--experimental-print-required-tlaは版によって性質が違います。Node 22、Node 24.20.0より前のNode 24、Node 26.5.0より前のNode 26では、場所を探すためにモジュールを評価します。Node 26.5.0以降とNode 24.20.0以降では、評価せずに場所を出力します。未知のコードや本番入口へ安易に付けず、実行してよいコードを隔離した再現環境で使ってください。変更の根拠はNode 26.5.0とNode 24.20.0のリリースノートにも記載されています。
上の最小例を診断するコマンドは次のとおりです。エラーを捕捉していない例なので、対応版ではトップレベルawaitの場所が標準エラー出力へ表示されます。
node --experimental-print-required-tla main.cjs
--no-require-moduleは非同期ESMを同期化する修正ではありません。同期ESMをrequire()する機能を無効化するだけで、トップレベルawaitを含むグラフの非同期性は消えません。
よくある質問
async関数内のawaitも原因ですか?
関数内のawaitだけならトップレベルawaitではありません。関数の外側で、モジュール評価中に使われるawaitが対象です。
トップレベルawaitを削除すべきですか?
必須ではありません。非同期初期化が必要ならimport()で待つのが自然です。設計を変えられる場合は、初期化処理を明示的なasync関数へ移す方法もあります。
ERR_REQUIRE_ESMとは違いますか?
古いNode.jsや同期ESMのrequire()を無効化した環境ではERR_REQUIRE_ESMが出る場合があります。対応版では同期ESMは読み込め、非同期ESMグラフに対してERR_REQUIRE_ASYNC_MODULEが発生します。
公式参考資料
切り分けの中心は「ESMかどうか」だけではなく、依存グラフを同期的に評価できるかです。トップレベルawaitを含むグラフはimport()で完了を待ち、同期読込を前提とするツールでは互換性も確認してください。


コメント