Claude Media
Claude CodeでECONNRESETが断続的に出る原因の切り分け方

Claude CodeでECONNRESETが断続的に出る原因の切り分け方

curlもブラウザーも通るのにClaude Codeだけ「Connection dropped (ECONNRESET)」が出る。経路の3系統とセッション肥大、計4系統の原因候補と、自分の回線でどれが当たるかを確かめる順序をまとめます。

API Error: Connection dropped (ECONNRESET) は、Claude CodeがAPIへ張った接続を相手側か経路上の機器にリセットされたときに出る表示です。VPNもプロキシも使っておらず、curl https://api.anthropic.com は通り、ブラウザーでclaude.aiも開ける。それでもClaude Codeだけが数分から数時間のあいだ失敗する、という報告がGitHubのissueに集まっています。

この症状に単一の原因は見つかっていません。issueには、回線ごとに別の原因が当たったという報告が並んでいます。この記事は、その報告から、経路の3系統とセッション肥大の計4系統に原因候補を分け、手元の回線でどれが当たるかを安く確かめる順序にしたものです。

ECONNRESETが出たとき、Claude Codeは何をしているか

画面には次のような表示が出ます。報告されている例です。

API Error: Connection dropped (ECONNRESET)
✻ Connection dropped (ECONNRESET) · Retrying in 4s · attempt 4/10

Connection dropped (ECONNRESET) は、APIへの接続失敗を示すエラーの1つです。接続の拒否(ECONNREFUSED)や名前解決の失敗(ENOTFOUND)とは別物で、相手側か経路上でリセットされたことを表します。コード別の一覧は「Unable to connect to API」の原因と対処にあります。

一時的な失敗は自動で再試行され、既定は最大10回です。バナーの attempt 4/10 はこの回数を指します。接続が回復すれば、キューにたまったメッセージは通ります。報告の多くが「ときどき直るのに、また落ちる」と書くのはこのためです。

ここで押さえたいのは、ECONNRESETが「サーバーが悪い」「ネットワークが悪い」のどちらも断定しない点です。報告者の1人は、メッセージが「インターネット接続、VPN、プロキシを確認」と案内するため、回線が正常でも調査が回線に向かってしまったと指摘しています。症状の名前から原因を決めず、手順で絞ります。

切り分けの全体像

報告された原因候補と、それぞれを見分ける手がかりを先に表にします。

候補典型的な状況見分ける手がかり
経路の問題典型的な状況特定の回線でだけ失敗する見分ける手がかりVPNやテザリングに替えると直る
IPv6経路の異常典型的な状況macOSでiCloudプライベートリレーが有効見分ける手がかりcurl -6 だけが失敗する
MTU(パケットサイズ)典型的な状況回線が1500未満のMTUを要する見分ける手がかりMTUを下げると直る
TLSの最初のパケット典型的な状況特定のISPで一定割合が失敗見分ける手がかり鍵共有を絞ったプローブで差が出る
セッションの肥大化典型的な状況長いセッションの終盤に増える見分ける手がかり新しいセッションでは出ない

1行目は経路全体の総称で、2〜4行目(IPv6・MTU・TLS)がその細分です。これに最後のセッション肥大を加えた計4系統が、この記事の切り分けの軸になります。順に、安く試せるものから見ていきます。

手順1: 経路を変えて再現するか確かめる

最初に確かめたいのは、回線を替えると症状が消えるかどうかです。

報告では、次の変更で直った例が複数あります。

  • スマートフォンのテザリングに切り替える
  • VPNを有効にする

スペイン、ドイツ、ポーランド、ベトナムの家庭用回線からの報告が、いずれも「VPNかテザリングなら直る」と書いています。同じ端末、同じバージョンで、回線だけが変数だったという書き方です。

直った場合、原因はClaude Codeの設定ではなく、その回線とAPIの受け口(報告では 160.79.104.10)のあいだにあります。以降の手順2〜4は、この場合の絞り込みです。

直らなかった場合は、手順5(セッション)と、公式の手順にある設定の確認に進みます。

一方、2つの異なるWi-Fiで再現したという報告もあり、回線を替えれば必ず直るわけではありません。同じメッシュ内の別のMacでは出ないという報告もあるため、端末側の要因も残ります。

手順2: IPv6と、macOSのiCloudプライベートリレー

curl はIPv6が失敗すると静かにIPv4へ切り替えます。そのため curl が通っていても、IPv6側だけが壊れている可能性が残ります。IPバージョンを固定して試します。

curl -6 -sS -o /dev/null -w 'v6: %{http_code}\n' \
  https://api.anthropic.com/v1/messages
curl -4 -sS -o /dev/null -w 'v4: %{http_code}\n' \
  https://api.anthropic.com/v1/messages

報告された診断では、v6が Connection reset by peer になり、v4は 405 を返しました。この組み合わせなら、IPv6経路が疑わしくなります。

macOSでは netstat -rn -f inet6 を見て、既定経路が utun インターフェースになっていないか確認します。報告者の環境では、これらはiCloudプライベートリレーのトンネルでした。scutil --nc list が空でも、システムのネットワーク拡張が張るため、VPNの確認では見つかりません。

報告された対処は2つです。

  1. システム設定でiCloud+のプライベートリレーをオフにする
  2. リレーは有効のまま、問題のあるWi-Fiの詳細で「IPアドレスの追跡を制限」だけをオフにする

2つ目で、リレーを他のネットワークでは使い続けられたとのことです。この報告者の自宅Wi-Fiでは、同じリレーが有効でもClaude Codeは正常でした。管理されたネットワークがQUIC(UDP/443)を遮断していて、リレーが半端に壊れていたと推測されています。

この系統の注意点は、同じスレッドの別の報告者が「自分の環境には当てはまらなかった」と書いていることです。その環境ではIPv4とIPv6の強制リクエストがどちらも約40msで成功し、utun 経由の既定経路もなく、TCPの確立後にIPv4でリセットされていました。curl -6 が通るなら、この手順は外れです。

デスクトップアプリは同じマシンで動くのに、CLIやVS Code拡張だけが落ちるという報告もあります。報告者は、デスクトップアプリのネットワークスタックがIPv4へ素早く切り替えるためではないかと推測しています。これは推測で、確認された仕様ではありません。

手順3: MTUを下げて直るか確かめる

パケットサイズを疑う報告が、ポーランドとスペインの回線から1件ずつ出ています。

ポーランドの報告者はパケットキャプチャで、次の点を示しました。

  • ClientHelloは1448バイトと100バイトの2セグメントで送られる
  • サーバー側の確認応答(ACK)は2つ目のセグメントしか受け取っていない
  • 約1RTT後に届くRSTのTTLが、サーバーのSYN-ACKと同じ55だった
  • 同じ形のClientHelloを cloudflare.com と www.google.com へ送ると成功する
  • インターフェースのMTUが1492以下なら通り、1500だと失敗する

TTLが一致するため、ルーターやISPのCGNAT機器ではなく、APIの受け口に近い側から返っているように見える、というのが報告者の読みです。

スペインの報告者は、同じ条件で10回ずつ試した結果を表にしています。

インターフェースのMTU成功した回数
1500成功した回数0/10(別の計測では8/52、3/40)
1492〜1400成功した回数各10/10

しきい値は1500と1492のあいだです。同じメッシュWi-Fiの別のMacはMTU 1500のまま動くため、端末側の要因も除けないと書き添えています。

自分のMTUは次のコマンドで見られます。

ifconfig en0 | grep mtu

Wi-Fiのインターフェース名が en0 と限らないので、環境に合わせて読み替えてください。

2件の報告が挙げた暫定の対処は、Wi-FiのMTUを下げることです。

sudo networksetup -setMTU Wi-Fi 1400

変更はシステム全体の通信に効きます。試した後は、元の値に戻す前提で使ってください。

この手順に、ローカルの中継プロキシでClaude Codeの鍵共有だけを変えても効かない、という副次的な知見があります。MTUが原因の回線では、リクエスト本体が大きなパケットで出ていくため、ClientHelloを小さくしても失敗が残ります。次の手順4で効いた方法が手順3の回線に効くとは限りません。

手順4: TLSの最初のパケットが落ちる回線

もう1つの仮説は、TLS 1.3のClientHelloに含まれる鍵共有です。Claude Codeのクライアントは、耐量子の X25519MLKEM768 を含めて接続を始めます。これは約1.7KBで、TCPでは2セグメントになります。従来の X25519:P-256 は約300バイトで1セグメントです。

スペインの報告者が同じ回線、同じ分に12回ずつ試した結果は次のとおりです。

提示した鍵共有成功リセット
X25519:P-256成功12リセット0
既定(X25519MLKEM768を含む)成功5リセット7
X25519:P-256成功12リセット0
既定(X25519MLKEM768を含む)成功6リセット6

ベトナムの報告者も、Go 1.25の既定では12回中0回、古典的な鍵共有だけなら12回中12回成功したと書いています。ホームルーターのファイアウォールを切っても変わらず、スマートフォンのテザリングでは動きました。

これを自分の回線で試すには、OpenSSL 3.5以降が必要です。macOS標準のLibreSSLには耐量子のグループがありません。

for g in X25519MLKEM768 X25519:P-256; do
  echo "== $g"
  for i in $(seq 12); do
    echo | openssl s_client -tls1_3 -groups "$g" \
      -connect api.anthropic.com:443 >/dev/null 2>&1 \
      && echo ok || echo reset
  done | sort | uniq -c
done

結果の読み方には3つの留意点があります。

  • 古典的な鍵共有だけが全部成功し、既定で失敗が出るなら、この仮説に当たります
  • どちらにも失敗が混じるなら、鍵共有以外の要因です。ドイツの報告では、耐量子の鍵共有が7/108、古典的な鍵共有も4/108で失敗しました
  • 同じ分に、openssl s_client では12/12成功し、Pythonのクライアントでは失敗した例もあります。ClientHelloの細部が効くため、1つのツールの結果で断定しないでください

このスレッドの書き込みは、どれも利用者の報告です。報告者は「Claude Code側で鍵共有を古典的なものだけに絞る設定がほしい」と求めています。ANTHROPIC_BASE_URL でローカルの中継を挟んで回避した報告はあるものの、Remote Controlは ANTHROPIC_BASE_URL が api.anthropic.com 以外だと起動しない、と同じ報告者が書いています。

手順5: 長いセッションの肥大化は別系統として切り分ける

もう1つ、経路ではなくセッションの側に着目した報告があります。ECONNRESETが続いたセッションを調べたところ、次の状態だったというものです。

  • 入力コンテキストが約30万トークン
  • セッションのトランスクリプトが3.9MB
  • ブラウザー操作ツールのスクリーンショットが17枚で、base64で約1.1MB

報告者は、巨大なリクエストが既存の失敗を引き起こしやすくしている、と推測しています。ただし本人が「スクリーンショットがTCPリセットを起こすことは証明していない」と書いています。別の報告者は、新しいセッションでは出ないと書いており、これは確認しやすい切り分けです。

試す順序は次のとおりです。

  1. /clear か新しいセッションで、短い入力を送る。出ないなら、手順1〜4の経路の問題とは別です
  2. 出るなら、経路の問題が残っています。新しいセッションでも、手順1から続けます
  3. 長いセッションでだけ出るなら、/compact で圧縮するか、スクリーンショットの多い作業の後は新しく始める

先にも触れたとおり、一時的な切断は再試行で吸収されます。どのくらいの頻度で失敗しているかは、手順の効果を見るときの物差しになります。

症状の出方から読む

ECONNRESETには2つの現れ方があります。

  • 接続の確立直後に落ちる。リクエストを送った約30ms後にエラーが返る、というポーランドの報告がこれです。手順2〜4の守備範囲です
  • 応答の途中で落ちる。Connection lost mid-response と表示される型です。ドイツの報告者は、同じ経路の上で、直接経由だと確立済みのストリームも切れたのに、特定のIPだけをVPNへ流すと両方が止まったと書いています。握手の失敗と途中切断が同じ原因で起きることがある、という報告です

応答の途中で切れる側の挙動は、ECONNRESETとは別にドキュメントに説明があります。切れた時点でClaudeがどこまで進んでいたかで扱いが変わり、完了したブロックまでは保持されます。詳しくは「Socket is closed」の原因と対処にまとめました。

直ったように見えても確認を重ねる

ログアウトとログインを試して「直った」と感じる罠が報告されています。ある報告者は、claude auth logout と claude auth login の直後に claude -p "say hello" が一度だけ成功し、トークンの問題だったと結論しました。4分後に症状は再発し、2回目のログイン直後は即エラーでした。

教訓は、何かを試した後に1回成功しても、直った証拠にならないという点です。間隔を空けて何度か送り、手順の前後で失敗率を比べてください。

同じ報告者は claude auth status の落とし穴も書いています。このコマンドはローカルの状態を読むだけで、サーバーに対してトークンを検証しません。認証が壊れているときも、loggedIn: true と表示されます。「認証は大丈夫」の根拠にはできません。

Claude Code側で確認できること

回線以外の確認として、公式のドキュメントにある手順を挙げます。

claude --debug

デバッグログは ~/.claude/debug/<セッションID>.txt に書かれます。あるMacの報告では、--debug のログに次の行が並びました。

API error (attempt 1/11): undefined Connection error.
Stale connection — disabling keep-alive for retry

古い接続を検出してkeep-aliveを切ったのに、次の試行も同じ失敗で終わっていた、という内容です。古い接続の再利用を避けても、症状は変わらなかったことになります。

再試行の回数を調整する環境変数もあります。CLAUDE_CODE_MAX_RETRIES は既定が10回です。無人のジョブでは CLAUDE_CODE_RETRY_WATCHDOG を 1 にすると、v2.1.199以降では切断などの一時的なエラーの既定回数が300回に上がり、約3時間分のバックオフを待ちます。ただし、これは待ち方を伸ばすだけで、手順2〜4にある回線そのものの問題は解決しません。

プロキシ越しの環境なら、HTTPS_PROXY が読み込まれているか、/status のProxy行で確認します。社内プロキシが原因の場合の切り分けは、先に挙げた記事のとおりです。

自分の回線の結果を残す

スレッドに書き込むとき、あるいは自分の記録として、次の項目を揃えると切り分けが進みます。報告者の多くが、回線の違いで結論が変わると書いているためです。

  • Claude Codeのバージョンとインストール方法(ネイティブかnpmか)
  • OSとMTU(ifconfig の結果)
  • ISP名と接続方式(PPPoE、CGNATの有無)
  • VPN、テザリング、別回線での結果
  • curl -4 と curl -6 の結果
  • 鍵共有を変えたプローブの成功/失敗の回数
  • 失敗が接続直後か、応答の途中か

まとめ

ECONNRESETの原因は1つに絞れていません。回線を替えて直るなら、手順2のIPv6、手順3のMTU、手順4の鍵共有の順に、安いものから試すと範囲が狭まります。回線を替えても出るなら、長いセッションの肥大化を疑い、新しいセッションで確かめます。

そして、1回の成功を直った証拠にしないことです。間隔を空けて繰り返し、前後の失敗率を比べて判断してください。

この記事を共有:XはてブLinkedIn