Fix curl Error 35: Missing Intermediate Cert in Caddy
Direct Answer: curl error 35 (SSL connect error) happens when the TLS handshake fails, most often because Caddy serves a leaf certificate without its intermediate. The client cannot build a trusted path to a root CA, so the connection aborts before any HTTP request is sent.
curl: (35) SSL connect error in Caddy usually means your server is not sending the intermediate certificate. Here is the exact cause and the fix.

At 2:14 a.m. the pager fired: payments-api was returning 100% errors. Nothing had been deployed in nine hours. The only change was a certificate renewal that ran at midnight.
What is curl error 35, and why is it so vague?
Error 35 is curl's generic "SSL connect error." It is thrown by the OpenSSL backend during the handshake, before a single HTTP byte moves. Expired certificates, protocol mismatches, missing intermediates, and SNI problems all collapse into the same number. That is why the error text alone sends people down the wrong path.
The discriminator is that error 35 is a connect error, not a certificate verify error. A verification failure prints curl: (60) SSL certificate problem: unable to get local issuer certificate. Error 35 means the handshake never completed far enough to produce that message.
How does Caddy build and serve a certificate chain?
Caddy's automatic HTTPS normally gets this right. When it issues via ACME, it stores a PEM bundle that already contains the leaf plus the intermediate chain, and tls serves that file directly.
The chain is positional, not tagged. The server sends certificates in order: leaf first, then intermediates, root omitted. A client walks that list, matching each issuer to the next certificate until it reaches a trusted root in its local trust store.
The intermediate is not optional. Let's Encrypt's current intermediate, R10/R11, is signed by ISRG Root X1. A client without R10 in the blob has no path from leaf to root, so the handshake aborts.
Three ways the chain breaks in Caddy:
tls /path/cert.pem /path/key.pempoints at a PEM that contains only the leaf, because someone exported it from a panel that strips the chain.- A config management agent overwrites the bundle with a single-cert file.
- Caddy is behind a load balancer terminating TLS with a manually uploaded certificate missing the intermediate.
What does the failure look like on the wire?
The symptom from the client side, captured in a CI pipeline that only failed after the midnight renewal:
$ curl -v https://api.example.dev/v1/health
* Trying 203.0.113.42:443...
* Connected to api.example.dev (203.0.113.42) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS alert, unknown CA (560):
* OpenSSL/3.0.13: error:0A000418:SSL routines::tlsv1 alert unknown CA
* Closing connection 0
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to api.example.dev:443
About the author
Admin SarangAI ยท AI Tools Editor
Part of the SarangAI editorial team covering AI tools, product releases, emerging technology trends, and practical web utilities for developers and creators.