SSL/TLS and certificate errors
TLS errors come from one of two phases: the handshake (protocol and cipher negotiation) or certificate validation (is this really the server I asked for?). Validation errors are the common ones, and every one of them has a correct fix that is not "turn verification off."
The validation failures
CERT_HAS_EXPIRED | Past its notAfter date. Renewals didn't run — or a machine's clock is wrong, which produces the same error with a valid cert. |
SELF_SIGNED_CERT_IN_CHAIN / DEPTH_ZERO_SELF_SIGNED_CERT | The chain ends in a certificate your trust store doesn't contain — internal CA, corporate TLS-inspecting proxy, or a genuinely self-signed dev cert. |
UNABLE_TO_VERIFY_LEAF_SIGNATURE | The server sent its leaf certificate but not the intermediate — browsers paper over this (AIA fetching), CLI tools and libraries do not. |
ERR_TLS_CERT_ALTNAME_INVALID / hostname mismatch | Valid certificate, wrong name: the cert's SANs don't include the hostname you dialed. Connecting by IP, by internal alias, or SNI misrouting on shared hosting. |
| Handshake failure / protocol version | No overlap in TLS versions or ciphers — typically an old client (TLS 1.0/1.1) against a modern server, or vice versa. |
See what the server actually serves
openssl s_client -connect api.example.com:443 -servername api.example.com | \ openssl x509 -noout -dates -subject -ext subjectAltName
That one command answers most tickets: the real expiry dates, the names the cert covers, and (in the full s_client output) whether the intermediate is in the served chain. Compare against what your code dials — including the port and the exact hostname, since SNI means different names can get different certificates from the same IP.
Fix the trust, don't disable it
NODE_TLS_REJECT_UNAUTHORIZED=0, verify=False,
InsecureSkipVerify: true — every stack has the same trapdoor, and it turns
"TLS error in staging" into "silent man-in-the-middle in production" the day the snippet
gets copied. The correct moves: renew (and automate renewal), add your internal CA to the
trust store (NODE_EXTRA_CA_CERTS, REQUESTS_CA_BUNDLE,
SSL_CERT_FILE, or the OS store), serve the full chain from the server, and dial
the name the certificate is actually for. Scope any dev-only exception to a single explicit
host, never process-wide.
Documented occurrences
116 analyzed errors across 26 libraries match this failure class. Each links to the thrown message, its source line, and documented fixes.
redis/redis-py
- Python wasn't built with SSL support
- Invalid SSL Certificate Requirements Flag: {cert_reqs}
- Invalid ssl verify flag: {flag}
- Python wasn't built with SSL support
- Invalid SSL Certificate Requirements Flag: {ssl_cert_reqs}
- +14 more in redis-py
guzzle/guzzle
- SSL CA bundle not found: %s
- SSL certificate not found: %s
- SSL private key not found: %s
- Invalid crypto_method_max request option: HTTP/2 and HTTP/3 require TLS 1.2 or higher
- Invalid crypto_method_max request option: maximum TLS version control is not supported by your version of cURL
- +9 more in guzzle
docker/cli
- failed to retrieve context tls info: ca.pem seems invalid
- TLS data for %s/%s/%s does not exist
- rotating to an external CA requires the `--%s` flag to specify the external CA's cert - to add an external CA with the current root CA certificate, use the `update` command instead
- failed to retrieve context tls info: %w
- TLS data for %s/%s/%s does not exist
- +7 more in cli
jackc/pgx
- no peer certificates for channel binding
- failed to parse certificate from server: {err}
- server refused TLS connection
- ssl request too short
- bad ssl request code
- +4 more in pgx
urllib3/urllib3
- urllib3 v2 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with {ssl.OPENSSL_VERSION!r}. See: https://github.com/urllib3/urllib3/issues/2168
- Can't connect to HTTPS URL because the SSL module is not available.
- No certificate for the peer.
- Can't create an SSLContext object without an ssl module
- TLS in TLS requires support for the 'ssl' module
- +3 more in urllib3
celery/celery
- SSL connection parameters have been provided but the specified URL scheme is redis://. A Redis SSL connection URL should use the scheme rediss://.
- Sorry, but you have to configure the * security_key * security_certificate, and the * security_cert_store configuration settings to use the auth serializer. Please see the configuration reference for more information.
- Non-RSA certificates are not supported.
- Unknown certificate: {id!r}
- Duplicate certificate: {id!r}
- +1 more in celery
redis/redis
- Could not negotiate a TLS connection: %s
- Could not negotiate a TLS connection: %s\n
- Could not negotiate a TLS connection: %s\n
- TLS Error: %s\n
- TLS Error: %s
gofiber/fiber
- failed to append certificate
- tls: AutoCertManager cannot be combined with CertFile/CertKeyFile
- tls: cannot load TLS key pair from certFile=%q and keyFile=%q: %w
- failed to parse client CA certificate from %q
- unsupported TLS version, please use tls.VersionTLS12 or tls.VersionTLS13
aio-libs/aiohttp
- ssl should be SSLContext, Fingerprint, or bool, got {ssl!r} instead.
- ssl should be SSLContext, Fingerprint, or bool, got {ssl!r} instead.
- SSL is not supported.
- Cannot initialize a TLS-in-TLS connection to host {req.url.host!s}:{req.url.port:d} through an underlying connection to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} [{type_err!s}]
- Handshake error: {key!r}
gohugoio/hugo
- failed to parse root certificate
- failed to parse certificate PEM
- failed to parse certificate: %v
- failed to verify certificate: %v
…and 16 more libraries — search for your exact message.
Other failure classes
- Connection failures: ECONNREFUSED, ECONNRESET, and friends
- DNS resolution errors: ENOTFOUND and getaddrinfo failures
- Timeouts: ETIMEDOUT, deadlines, and hung requests
- HTTP status errors: handling 4xx and 5xx responses
- Authentication and authorization failures
- Parsing and encoding errors: unexpected token, malformed input