結論

npm error code ECONNRESET は、接続が相手側から切られたという意味です。npm はこのコードを他のネットワーク系と同じ分岐で扱うため、固有の説明は出ません。表示されるのは「ネットワーク接続に関する問題である」「多くの場合は中継の設定かネットワーク設定に問題がある」という2文と、中継設定の確認を促す1文だけです。

つまり文言からは原因を絞れません。切り分けの材料は3つあります。どの回線で起きるか、失敗する対象が毎回同じか変わるか、そして失敗するまでの時間です。

npm は取得に失敗した場合、既定で2回まで再試行します。待ち時間は10秒から始まり、上限は1分です。これを踏まえると、実行してすぐ落ちる場合と、数十秒かけて落ちる場合では見るべき場所が違います。

最初に確認すること

まず、経路の設定を並べて確認します。

npm config get proxy
npm config get https-proxy
npm config get registry
npm config get maxsockets

proxyhttps-proxynull なのに社内の回線から実行している場合、原因1に当たります。環境変数側だけに設定されていることもあるため、そちらも見てください。

printenv | grep -i proxy

次に、失敗する対象が毎回同じかを確かめます。

npm install --loglevel verbose 2>&1 | tail -40

対象が実行ごとに変わるなら、特定のパッケージではなく接続の総量が問題です。同じ対象で止まるなら、その向き先が届いていません。

原因別の確認方法と解決策

原因1:中継の設定が npm に渡っていない

社内の回線からのみ失敗する場合です。npm の説明文も、まずこの可能性を挙げます。

確認方法は設定値の突き合わせです。公式の説明によれば、HTTP_PROXYhttp_proxy の環境変数が設定されていれば、その内容が利用されます。npm 側の設定と環境変数のどちらか一方だけに値が入っていると、経路が定まりません。

対処は、組織から指定されている中継先へ揃えることです。

npm config set proxy http://proxy.example.com:8080
npm config set https-proxy http://proxy.example.com:8080

中継先を通さない宛先がある場合は、除外する一覧も設定してください。

原因2:同時に張る接続が多すぎる

依存の多い環境や継続的インテグレーションで起きます。失敗する対象が実行ごとに変わるのが特徴です。

npm は同じ向き先に対して既定で15本まで接続を張ります。経路上の機器がこれを過剰と判断すると、途中の接続が切られます。

確認方法は現在値の照会と、失敗対象の変化です。

npm config get maxsockets

対処は上限を下げることです。

npm install --maxsockets 5

改善するなら確定です。恒久的に設定する場合は、実行環境ごとの設定ファイルへ書いてください。

原因3:再試行が足りていない

時間をおくと成功する場合です。一時的な切断が、既定の再試行の範囲を超えて続いています。

確認方法は設定値と経過時間の照合です。

npm config get fetch-retries
npm config get fetch-retry-mintimeout

既定では2回まで再試行し、最初の待ち時間は10秒です。実行から十数秒で落ちているなら、再試行は使い切られています。

対処は回数と待ち時間を増やすことです。

npm install --fetch-retries 5 --fetch-retry-maxtimeout 120000

ただし、これは切断そのものを解消しません。原因1や原因2を確認したうえで、それでも断続的に切れる場合の緩和策として使ってください。

原因4:経路上の検査装置が接続を切っている

組織の回線でのみ失敗し、証明書に関する警告が併せて出る場合です。通信を復号して検査する装置が経路にあると、npm 側の検証が通らず接続が切られます。

確認方法は、同じ経路で他の手段が通るかの比較です。

npm config get registry

対処は、組織が配布している証明書を登録することです。

npm config set cafile /path/to/corporate-ca.pem

strict-ssl を無効にすると通ることがありますが、これは検証そのものを止める操作です。公式の設定では既定で有効になっています。無効化は、なりすましを検知できなくなる点を理解したうえで、一時的な切り分けに限って使ってください。

近いエラーとの違い

ENOTFOUND は名前を引けなかった場合です。npm の実装では ECONNRESET と同じ分岐に入るため、表示される説明文は同一になります。区別できるのはコードの行だけです。接続が切られたのではなく、宛先が分からない状態を指します。

ETIMEDOUT は応答が返らないまま時間切れになった場合です。こちらも同じ分岐で、説明文は変わりません。切られたのか返ってこないのかで、疑う相手が変わります。

CERT_HAS_EXPIRED証明書の期限切れです。接続は成立しており、検証の段階で止まっています。原因4と経路は近いものの、失敗する場所が違います。

E401レジストリからの認証要求です。通信そのものは成立しています。

参考資料


免責事項:本記事の内容は、執筆時点の公開情報をもとに作成したものです。ソフトウェアの仕様は予告なく変更されることがあります。最新の情報は各ツールの公式サポートページをご確認ください。本記事の情報を利用した結果生じたいかなる損害についても、著者および運営者は責任を負いかねます。