結論

npm error code EAI_AGAIN は、名前を引く処理が一時的に失敗したという意味です。syscall の行には getaddrinfo が入ります。宛先のサーバーへ接続する前の段階で止まっており、レジストリの応答内容は関係ありません。

注意すべき点があります。npm はこのコードに専用の説明を持っていません。実装のコードごとの分岐には ENOTFOUNDEAI_FAIL はありますが、EAI_AGAIN は含まれておらず既定の扱いになります。したがって、ECONNRESET のときに出る「中継設定を確認してください」という案内も表示されません。表示されるのは、失敗した要求の内容を示す1文だけです。

切り分けの材料はエラー文の末尾にあります。getaddrinfo EAI_AGAIN の後ろに、引こうとした名前が入ります。ここがレジストリの名前なのか、中継先の名前なのかで、疑う場所が変わります。

最初に確認すること

まず、失敗している名前を特定します。

npm install 2>&1 | grep -o "EAI_AGAIN [^ ]*"

次に、レジストリへ届くかを npm 自身の手段で確かめます。

npm ping

このコマンドは現在の向き先へ疎通を試み、往復にかかった時間を表示します。ここで同じコードが返れば、原因は取得処理ではなく経路にあります。成功したり失敗したりする場合は、一時的な不調です。

名前を引く側の設定も確認してください。

cat /etc/resolv.conf
npm config get registry
npm config get proxy

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

原因1:コンテナから名前を引く先へ届いていない

コンテナの中でのみ失敗する場合です。実行環境が参照している宛先が、そのコンテナからは到達できません。

確認方法は、コンテナの内側から見ることです。

docker compose exec app sh -c 'cat /etc/resolv.conf'

記載されている宛先が、コンテナの外側でしか使えないものになっていることがあります。その場合、外側では成功して内側でだけ失敗します。

対処は、届く宛先を指定し直すことです。

services:
  app:
    dns:
      - 1.1.1.1

組織のネットワークでは、内部の宛先を指定する必要がある場合があります。管理者の指定に従ってください。

原因2:中継先を経由せず自分で名前を引いている

社内の回線で、中継の設定は入っているのに失敗する場合です。エラー文の末尾に出ている名前が、中継先ではなく接続先になっていれば、中継を経由していません。

確認方法は設定値と失敗名の突き合わせです。

npm config get proxy
npm config get https-proxy
npm config get noproxy

除外の一覧に接続先が含まれていると、その宛先だけ中継を通しません。結果として自分で名前を引こうとして失敗します。

対処は、設定を揃えたうえで除外の一覧を見直すことです。環境変数側にだけ値が入っている場合も同じ結果になるため、両方を確認してください。

原因3:名前を引く先が一時的に応答していない

時間をおくと成功する場合です。このコードは名称のとおり、再試行すれば通る可能性がある種類の失敗を表します。

確認方法は繰り返しの実行です。

npm ping

数回実行して成功と失敗が混ざるなら確定です。すべて失敗するなら、一時的ではありません。

対処は、宛先を安定したものへ変えるか、復旧を待つことです。継続的インテグレーションでは、この形の失敗が一定の割合で混ざることがあります。再試行の設定を増やしても、名前を引く段階の失敗は npm の取得の再試行では吸収されないことがあるため、実行そのものをやり直す仕組みのほうが確実です。

原因4:指定した向き先の名前が引けない

社内のレジストリを指定したときだけ失敗する場合です。エラー文の末尾に、その名前が出ます。

確認方法は向き先の照会です。

npm config get registry
npm config list | grep registry

範囲ごとに向き先を変えている場合、そちらの設定も確認してください。対処は、その名前を引ける回線から実行することです。社外の回線や、接続していない状態では引けません。

向き先の指定そのものが古い場合もあります。組織の案内と突き合わせてください。公開レジストリへ切り替える対処は、社内の方針に反する場合があります。切り替える前に確認してください。

近いエラーとの違い

ENOTFOUND は、その名前が存在しないという結果です。EAI_AGAIN が一時的な失敗を表すのに対し、こちらは確定した結果になります。npm の実装ではこちらだけがネットワーク系の分岐に含まれており、中継設定の確認を促す説明が表示されます。説明文の有無で見分けられます。

ECONNRESET は、名前は引けたが接続が切られた場合です。段階が1つ先に進んでいます。

ETIMEDOUT は、接続を試みたが応答が返らなかった場合です。こちらも名前は引けています。

CERT_HAS_EXPIRED は接続が成立したあとの検証で止まっています。名前解決とは無関係です。

参考資料


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