エラーメッセージ
curl: (56) OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0
別の表記
- curl: (56) OpenSSL SSL_read: OpenSSL/3.5.7: error:0A000126:SSL routines::unexpected eof while reading, errno 0
最近の curl のリリースでは、「SSL_read:」の後に TLS ライブラリのバージョン(例:「OpenSSL/3.5.7:」)が挿入されます。OpenSSL 1.1.1 はこの状況をこのようには報告しませんでした。1.1.1 では、同じ切り詰めは通常「curl: (18) transfer closed with N bytes remaining to read」として表示されます。
curl (OpenSSL 3 backend) — CURLE_RECV_ERROR, SSL_R_UNEXPECTED_EOF_WHILE_READING
このエラーの意味
TLS 接続が確立してデータが流れていたところで、curl がまだ続きのデータを待っているにもかかわらず、相手側が TLS の close_notify を送らずに TCP 接続を閉じました。close_notify がない状態は切り詰め攻撃と同じ見え方をするため、OpenSSL 3 はこのような突然の終了を、通常のストリームの終わりではなくエラーとして報告します。curl はこれを受信の失敗(終了コード 56)として報告します。
発生する理由
応答の途中でサーバープロセスが停止またはタイムアウトした
よくあるタイムアウトやメモリ不足で強制終了されたアプリケーションのワーカー、PHP-FPM や Gunicorn のワーカーの再起動、処理を諦めたアップストリームなどにより、レスポンスボディの送信中にソケットが切断されます。
ミドルボックスが接続を切断した
よくあるアイドル時間や最大接続時間の制限を課すファイアウォール、NAT ゲートウェイ、企業のプロキシ、ロードバランサーは、長いダウンロードや時間のかかるレスポンスを TCP レベルで切断することがあります。その場合、サーバーからの TLS のシャットダウンは行われません。
サーバーが close_notify なしでレスポンスを終了している
ときどき一部の組み込み Web サーバー、古いバージョンの IIS、自作の TLS サーバーは、TLS のシャットダウンを行わずにソケットを閉じます。接続の切断で終わりを示す HTTP レスポンスの場合、OpenSSL 3 のクライアントはそうしたレスポンスをすべてこのエラーとして報告します。
ボディサイズの制限で転送が中断された
ときどきアップロードの制限(client_max_body_size や WAF のルール)やダウンロードの割り当て上限によって、本来の 413 や 403 のレスポンスを返す代わりに接続がリセットされることがあります。
修正方法
- 1.
どのホップが接続を閉じているかを特定する
エラーまでに何バイト転送され、何秒経過したかを記録してから、バックエンドに直接同じリクエストを送ってください。切りのよい秒数で切断されている場合は、プロキシやロードバランサーのタイムアウトが疑われます。
bash # How much arrived, and for how long, before the connection died? curl -sv --trace-time https://api.example.com/export.csv -o out.csv 2>&1 | tail -20 # Same request directly to the backend, bypassing the proxy / load balancer curl -sv --resolve api.example.com:443:10.0.0.12 https://api.example.com/export.csv -o out.csv - 2.
発動しているタイムアウトを延長する
接続を切断しているコンポーネントの制限値を、正当なレスポンスにかかる最長の時間より大きくするか、遅いエンドポイントの応答を速くしてください(大きなエクスポートはストリーミングかページ分割で返します)。
text # nginx in front of a slow upstream (both default to 60s) proxy_read_timeout 300s; proxy_send_timeout 300s; # Load balancers: set the idle timeout above the longest legitimate response time - 3.
冪等な転送を再試行する
不安定な回線でのダウンロードでは、curl に再試行と再開をさせてください。これは、サーバー側を調査している間にクライアント側で症状に対処する方法です。
bash # For idempotent downloads: retry, and resume where the transfer stopped curl --retry 5 --retry-all-errors -C - -o big.iso https://downloads.example.com/big.iso - 4.
サーバーのコード:TLS 接続を正しく閉じる
ソケットを閉じる前に close_notify を送信し(OpenSSL では SSL_shutdown、Python では unwrap()、Go では tls.Conn の Close())、HTTP のボディを Content-Length または chunked エンコーディングで区切って、正常な終了が明確にわかるようにしてください。
python # Server code: shut TLS down cleanly so the peer receives close_notify conn.unwrap() # Python ssl.SSLSocket: sends close_notify before closing conn.close()
関連するエラー
error:0A000126:SSL routines::unexpected eof while readingOpenSSL 3[SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocolPython ssl module (OpenSSL)GnuTLS recv error (-110): The TLS connection was non-properly terminated.git over HTTPS with libcurl-gnutls (Debian, Ubuntu)curl: (35) TLS connect error: error:0A00010B:SSL routines::wrong version numbercurl (OpenSSL backend)