npmのERESOLVEエラーを直す|依存関係の競合を安全に解消する手順
npm installでERESOLVEが出たときに、競合パッケージと要求バージョンを読み、package.jsonとlockfileを最小限の変更でそろえる手順を解説します。
npm installでERESOLVE unable to resolve dependency treeと表示されたら、強制オプションを付ける前に立ち止まります。読むべきは「どのパッケージが、どの版を要求しているか」です。多くの場合、直接使うパッケージと、プラグインなどのpeerDependencies(一緒に使う相手の対応版)の範囲が重ならない競合です。
この記事では、エラーの読み方、対応版の選び方、lockfile(依存の記録ファイル)の更新、テストまでを順番に進めます。例に出す名前と版は説明用です。挙動の確認対象はnpm CLI v11の公式資料です。npmの挙動はメジャー版(大きな版)や設定で変わることがあるので、実際の対応版はその時点の公式案内で確認してください。
ERESOLVEは「互換性の競合を見つけた」合図
ERESOLVEは、npmが「全員の要求を同時に満たす依存ツリー(パッケージの組み合わせ)を決められなかった」ことを示すエラーです。何かが壊れたのではなく、矛盾を先に見つけて止まってくれた状態です。
npm公式のpackage.json資料によると、peerDependenciesは「プラグインが、どの版のホスト(土台のライブラリ)と一緒に動けるか」を表す欄です。npm v7以降は、このpeerDependenciesも既定でインストールされます。そのため、要求が矛盾するプラグインを追加すると、npmは依存ツリーを解決できずエラーを出すことがあります。
たとえば、プロジェクトがui-library@5を使っているのに、追加したプラグインがui-library@^4.0.0(4系だけ)を要求している状態です。
さらに、npm公式の実装済みRFC(仕様の決定文書)には、競合の扱い方が3つ書かれています。
- strictモード: peer競合をERESOLVEとして止める
- forceモード: 警告だけ出して競合を上書きする
- 既定モード: プロジェクト直下の直接依存は厳しく止め、深い階層の依存は警告して上書きする
つまり「自分のpackage.jsonに書いたパッケージ同士の競合」は既定でエラーになりやすく、「奥の方の間接的な競合」は警告で通ることがあります。同じERESOLVEでも原因はさまざまです。推測せず、実際のエラー全文を読むところから始めます。
エラー全文から競合の3点を読み取る
ERESOLVEの全文を途中で切らずに保存し、次の形の行を探します。
Found: [email protected]
Could not resolve dependency:
peer ui-library@"^4.0.0" from [email protected]
読み方は次のとおりです。
Found:の行 = いま入っている版(この例では[email protected])fromの後ろ = 競合を起こしている相手([email protected])peer ...@"..."の範囲 = 相手が許している版の範囲(^4.0.0)
まずこの3点を作業メモへ写します。ここが決まれば、直す場所はほぼ特定できています。
すでにインストール済みのパッケージが「どの経路から入ったのか」を知りたいときは、npm explain ui-libraryが使えます。npm公式のnpm explain資料によると、このコマンドは指定したパッケージが入った原因を、依存の連鎖(AがBを呼び、BがCを呼ぶ、のつながり)で表示します。別名のnpm whyでも同じです。ただし説明できるのは「現在のプロジェクトに入っている」パッケージです。インストール自体が失敗してnode_modulesに無いものは、ERESOLVE全文、package.json、package-lock.jsonを読んで追いかけます。
package.jsonでは、dependenciesとdevDependenciesから競合した名前を探します。固定版なのか、^や~付きの範囲指定なのかを確認します。ワークスペース(1つのリポジトリに複数プロジェクトを入れる構成)では、エラーに出た配下のpackage.jsonも見ます。
互換する組み合わせを選び、直接依存を1組だけ直す
版の数字の意味はSemVer(セマンティック バージョニング)2.0.0で決められています。MAJOR(1つ目)は互換性が壊れる変更、MINOR(2つ目)は後方互換の機能追加、PATCH(3つ目)は後方互換の修正です。ただしこれは「番号の付け方のルール」であって、個々のパッケージが実際にそのとおり互換である保証ではありません。判断は、peerDependenciesの範囲、公式リリースノート、実際のテストの3つを組み合わせます。
候補の版が何を要求しているかは、npmレジストリ(パッケージの倉庫)から確認できます。
npm view ui-plugin versions --json
npm view ui-[email protected] peerDependencies
npm view ui-plugin@latest peerDependencies
latest(最新)が自分の構成に最適とは限りません。候補が見つかったら、公式リリースノートで破壊的変更、Node.jsの対応範囲、移行手順も読みます。公式情報で互換性を判別できなければ「※要確認」として保留します。
選択肢は主に3つと、一時回避の1つです。
| 選択肢 | 向いている状況 | 主な確認点 | 注意点 |
|---|---|---|---|
| プラグインを上げる | いまのホスト版を維持したい | 新版のpeerDependenciesと移行手順 | プラグイン側の破壊的変更 |
| ホストを戻す | プラグインに対応版や代替がない | 他の依存が旧版を許すか | 新版で使っていた機能や修正が失われないか |
| 別パッケージへ替える | 互換版がなく、保守状況にも不安がある | 必要な機能・ライセンス・移行量 | 設定やAPIの書き換えが必要 |
| 強制オプションで一時回避 | 原因の切り分けだけを行う | 実行時テストとCIの同一条件 | 互換性の競合そのものは残る |
方針を決めたら、元へ戻せる状態(gitのコミットなど)を用意し、直接依存を1回に1組だけ変えます。実際の版は、確認した値へ置き換えてください。
npm install ui-[email protected]
複数のメジャー更新を混ぜると、不具合が出たときに原因を切り分けられません。実行後はpackage.jsonとpackage-lock.jsonの差分を見ます。lockfileは手で部分編集せず、npmに更新させます。差分が対象パッケージの周りに収まっていれば前進です。想定外の大量更新が出たら、npmやNode.jsの版、作業フォルダ、元のlockfileを見直します。端末ごとに版が違うときはNode.jsのバージョン不一致を直す手順も確認してください。
強制オプションを避け、テストとCIで解決を証明する
エラー文には--forceや--legacy-peer-depsという逃げ道が表示されます。しかしnpm公式のConfig資料では、legacy-peer-depsは依存ツリーを作るときにpeerDependenciesを完全に無視する設定で、互換性の契約を守らせないため推奨されないと説明されています。--forceはさらに広く、ルート直下のpeer競合の押し通しだけでなく、対応エンジン(Node.jsの版)の不一致など複数の保護をまとめて外します。「インストールが通った」と「互換性が解決した」は同じではありません。
原因の切り分けに一時的に使う場合も、「採用するかどうかの判断基準」「lockfileへの影響」「元へ戻す条件」を先に決めます。npm公式のnpm ci資料によると、依存ツリーへ影響するフラグでlockfileを作った場合、npm ci(CI用のクリーンインストール)にも同じフラグが必要になることがあります。自分の手元だけ通る構成は、チームやCIで再現できません。
ERESOLVEの表示が消えたら、次の順で証拠を残します。
npm ciで入れ直す。npm ciはpackage.jsonとlockfileが一致しないと、lockfileを書き換えずにエラーで止まります。開始前に既存のnode_modulesは自動で削除されます。役割の違いはnpm ciとnpm installの違いで整理しています- ビルド、型検査、単体テストを回す
- 更新したプラグインを使う代表機能を実際に動かす。初期化や設定の読み込みは、インストール成功だけでは検査されません。正常系だけでなく設定不足も試します
- CIでも同じ結果になるか確かめる。GitHub公式のNode.js向けCI資料の例も、
npm ciのあとにビルドとテストを実行する順になっています。例に載っている具体的な版や部品は更新されるので、この検証の順番だけを参考にします
再発に備えて、ERESOLVE全文、選んだ版、実行コマンド、差分、テスト結果を1つの作業メモへ残します。更新後の確認項目を定型化するなら、AIコーディングの回帰テスト手順も参考になります。
よくある質問
ERESOLVEが出たらpackage-lock.jsonを削除してよいですか?
最初の手段にはしません。lockfileを消して作り直すと、無関係な間接依存まで一斉に変わる可能性があります。先に競合の3点(現在版・競合元・要求範囲)を特定し、package.jsonの直接依存を直してから、npmにlockfileを更新させます。どうしても再生成が必要な場合は、元のlockfileを復元できる状態にしてから行い、再生成後の差分を検査します。
—legacy-peer-depsでインストールできたら解決ですか?
いいえ。これはpeerDependenciesを無視して進める設定で、互換版を選んだことにはなりません。npm公式資料も、契約を強制しないため非推奨としています。使うのは原因調査の一時比較までにして、採用する前にビルド・テスト・代表機能の動作を確認します。
—forceと—legacy-peer-depsの違いは何ですか?
--legacy-peer-depsは、peer依存の解決だけを無視する設定です。--forceは、peer競合の上書きを含めて、npmの複数の安全保護をまとめて外す、さらに広い設定です。どちらも「要求範囲の不一致」そのものは直しません。常用せず、互換版をそろえる方法を先に検討します。
npm ciでだけERESOLVEになるのはなぜですか?
npm ciはpackage.jsonとlockfileが一致しないと、lockfileを更新せずに終了する決まりだからです。また、lockfileを作ったときに依存ツリーへ影響するフラグを使っていた場合、CI側にも同じフラグが要ることがあります。ローカルとCIのNode.js、npm、設定ファイル、lockfileを比べてください。
AIにERESOLVEの修正を頼むとき、何を渡せばよいですか?
材料は6点です。ERESOLVE全文、package.json、package-lock.json、node --versionの結果、npm --versionの結果、直前に実行したコマンド。あわせて条件を付けます。「変更は直接依存1組まで」「強制フラグの常用とlockfileの削除は勝手にしない」「npm ci・ビルド・テストの成功と、差分の説明を完了条件にする」。ここまで固定すると、AIの作業をあとから安全に検収できます。
まとめ
ERESOLVEは、npmが互換性の矛盾を先に見つけて止めてくれた合図です。強制フラグで黙らせるのではなく、原因の1組を直します。次の3つから始めてください。
- エラー全文を保存し、
Foundの現在版・fromの競合元・peerの要求範囲の3点をメモする - 公式の
peerDependenciesとリリースノートで互換版を選び、直接依存を1回に1組だけ変えて、lockfileはnpmに更新させる npm ci→ビルド→テスト→代表機能の順で確かめる。AIに任せるときも、この材料と合格条件をセットで渡す
公式一次情報
確認日: 2026-07-26
- package.json | npm Docs: peerDependenciesの用途と、npm v7以降は既定でインストールされ競合時にエラーになり得ることの説明
- Config | npm Docs: legacy-peer-depsがpeerDependenciesを完全に無視するため非推奨であることと、forceが複数の保護を外す設定であることの説明
- npm-explain | npm Docs: インストール済みパッケージが入った原因を依存の連鎖で表示するコマンドの説明
- npm-ci | npm Docs: lockfileとpackage.jsonが一致しないと更新せず終了する動作と、lockfile作成時のフラグがCIにも必要になり得ることの説明
- Handling Conflicting peerDependencies: peer競合をstrict・force・既定モードでどう扱うかを定めたnpm公式の実装済みRFC
- Semantic Versioning 2.0.0: MAJOR・MINOR・PATCHの意味を定めた版番号の仕様
- Building and testing Node.js - GitHub Docs: npm ciのあとにビルドとテストを実行する公式のCI構成例
続き(結論と実データ)はnoteに置いています
ここでは手順のところまで書きました。実際に出た数字、うまくいかなかった条件、そのまま使える設定ファイルは、 note の記事にまとめてあります。