CI "curl: (35) SSL connect error" - TLS Negotiation Failed
By Daniel Zoghalchali·Latchkey
curl exit code 35 is CURLE_SSL_CONNECT_ERROR - the socket connected but securing it with TLS failed. The handshake stalled, was reset, or could not agree on parameters.
What this error means
A curl https://... call fails with curl: (35) SSL connect error (sometimes OpenSSL ... unexpected eof or a handshake reset). The connection reached the server, so it is not DNS - securing it failed. A retry frequently succeeds when the cause was a transient blip.
CI log
curl: (35) OpenSSL/3.0.2: error:0A000126:SSL routines::unexpected eof while reading
# or
curl: (35) SSL connect error
Common causes
A transient handshake failure
A briefly overloaded server or a congested path can drop or stall the TLS handshake mid-negotiation, surfacing as a (35) that clears on retry.
A proxy or TLS mismatch in the path
A TLS-intercepting proxy, or a protocol/cipher mismatch, can break the handshake. Unlike a transient blip, this recurs until the trust/proxy config is fixed.
How to fix it
Retry the request
A one-off handshake stall usually clears on a clean retry.
Terminal
curl --retry 5 --retry-delay 2 --retry-all-errors -fSL "$URL" -o out
Rule out a proxy / TLS mismatch if it recurs
Check for an intercepting proxy (env | grep -i proxy) and trust its CA rather than disabling verification.
Test verbosely (curl -v https://host) to see where the handshake fails.
Pull through a closer mirror/cache to cut handshake round trips.
How to prevent it
Retry TLS-dependent network steps with backoff.
Provide the proxy/corporate root CA to the trust store, not per-command flags.
Mirror or cache registries to reduce handshake round trips.
Frequently asked questions
What causes ""curl: (35) SSL connect error""?
A briefly overloaded server or a congested path can drop or stall the TLS handshake mid-negotiation, surfacing as a (35) that clears on retry.
How do I fix "curl: (35) SSL connect error"?
A one-off handshake stall usually clears on a clean retry.
Can Latchkey fix this automatically?
Yes. Latchkey runs your GitHub Actions on managed runners that detect this failure, apply the fix, and retry the job automatically - self-healing is on by default.