Skip to content
ecdsa.com
curl (OpenSSL 3 backend)curl

Error message

curl: (56) OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0

Also printed as

  • curl: (56) OpenSSL SSL_read: OpenSSL/3.5.7: error:0A000126:SSL routines::unexpected eof while reading, errno 0

Recent curl releases insert the TLS library version after "SSL_read: " (for example "OpenSSL/3.5.7: "). OpenSSL 1.1.1 did not report this condition this way; on 1.1.1 the same truncation usually shows as "curl: (18) transfer closed with N bytes remaining to read".

curl (OpenSSL 3 backend) — CURLE_RECV_ERROR, SSL_R_UNEXPECTED_EOF_WHILE_READING

What it means

The TLS connection was established and data was flowing, then the peer closed the TCP connection without first sending TLS close_notify, while curl still expected more data. OpenSSL 3 reports such an abrupt end as an error instead of a normal end of stream, because a missing close_notify is how a truncation attack looks. curl reports it as a receive failure (exit code 56).

Why it happens

How to fix it

  1. 1.

    Find out which hop closes the connection

    Note how many bytes and how many seconds pass before the error, then repeat the request directly to the backend. A cut at a round number of seconds points to a timeout in a proxy or load balancer.

    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. 2.

    Raise the timeout that fires

    Increase the limit in the component that cuts the connection above the longest legitimate response time, or make the slow endpoint respond faster (stream or paginate large exports).

    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. 3.

    Retry idempotent transfers

    For downloads over unreliable links, let curl retry and resume. This treats the symptom on the client while the server side is investigated.

    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. 4.

    Server code: close TLS connections properly

    Send close_notify before closing the socket (SSL_shutdown in OpenSSL, unwrap() in Python, Close() on a Go tls.Conn), and delimit HTTP bodies with Content-Length or chunked encoding so a clean end is unambiguous.

    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()

Related errors

Browse the full signature error database