Skip to content
Latchkey

Python "ssl.SSLError" in Tests - Fix TLS Handshake Failures in CI

A test opened a TLS connection that failed during the handshake. The hostname, port, protocol, or trust store is wrong - often a test client speaking HTTPS to a plain-HTTP fixture, or a self-signed cert the runner doesn’t trust.

What this error means

A test that talks to a server (a fixture, a localhost stub, or a real endpoint) raises ssl.SSLError - frequently WRONG_VERSION_NUMBER or CERTIFICATE_VERIFY_FAILED - during the handshake, before any request body is sent.

Python traceback
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1006)
# or
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify
failed: self signed certificate (_ssl.c:1006)

Common causes

HTTPS client against an HTTP server

WRONG_VERSION_NUMBER almost always means the client tried a TLS handshake with a server speaking plain HTTP - a test pointed https:// at a fixture that only serves http://.

Self-signed or untrusted test certificate

A local test server presents a self-signed certificate the runner’s trust store doesn’t contain, so verification fails during the handshake.

How to fix it

Match the scheme to the server

If the fixture serves plain HTTP, use http://. Only use https:// when the test server actually terminates TLS.

Python
# fixture serves plain HTTP - use http, not https
resp = client.get("http://localhost:8000/health")

Trust the test certificate explicitly

For a self-signed test server, point the client at its CA bundle rather than disabling verification globally.

Python
import ssl
ctx = ssl.create_default_context(cafile="tests/certs/test-ca.pem")
# pass ctx to your client, e.g. urlopen(url, context=ctx)

How to prevent it

  • Keep test fixtures’ scheme (http vs https) consistent with what they serve.
  • Ship a dedicated test CA and trust it explicitly instead of disabling verification.
  • Centralize the test server URL so the scheme isn’t hardcoded in many places.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →