python/cpython · error · ValueError
ssl_handshake_timeout is only meaningful with ssl
Error message
ssl_handshake_timeout is only meaningful with ssl
What it means
Raised by create_connection when ssl_handshake_timeout is given but ssl is not. The handshake timeout bounds how long the TLS handshake may take; it only exists in the TLS code path, so asyncio rejects it for plaintext connections as a likely configuration error.
Source
Thrown at Lib/asyncio/base_events.py:1106
if server_hostname is None and ssl:
# Use host as default for server_hostname. It is an error
# if host is empty or not set, e.g. when an
# already-connected socket was passed or when only a port
# is given. To avoid this error, you can pass
# server_hostname='' -- this will bypass the hostname
# check. (This also means that if host is a numeric
# IP/IPv6 address, we will attempt to verify that exact
# address; this will probably fail, but it is possible to
# create a certificate for a specific IP address, so we
# don't judge it here.)
if not host:
raise ValueError('You must set server_hostname '
'when using ssl without a host')
server_hostname = host
if ssl_handshake_timeout is not None and not ssl:
raise ValueError(
'ssl_handshake_timeout is only meaningful with ssl')
if ssl_shutdown_timeout is not None and not ssl:
raise ValueError(
'ssl_shutdown_timeout is only meaningful with ssl')
if sock is not None:
_check_ssl_socket(sock)
if happy_eyeballs_delay is not None and interleave is None:
# If using happy eyeballs, default to interleave addresses by family
interleave = 1
if host is not None or port is not None:
if sock is not None:
raise ValueError(
'host/port and sock can not be specified at the same time')
View on GitHub (pinned to bc6749cc3b)
Solutions
- Only pass ssl_handshake_timeout when ssl is truthy: include it in the same conditional branch as ssl.
- If plaintext is intended, remove the timeout argument.
- Group all TLS-only kwargs (ssl, server_hostname, ssl_handshake_timeout, ssl_shutdown_timeout) so they are set or omitted together.
Example fix
// before
await loop.create_connection(proto, h, p, ssl_handshake_timeout=10) # no ssl
// after
if ctx is not None:
t, p_ = await loop.create_connection(proto, h, p, ssl=ctx,
ssl_handshake_timeout=10)
else:
t, p_ = await loop.create_connection(proto, h, p) Defensive patterns
Strategy: validation
Validate before calling
tls_kwargs = {}
if ctx is not None:
tls_kwargs.update(ssl=ctx, ssl_handshake_timeout=10, ssl_shutdown_timeout=10) Try / catch
try:
await loop.create_connection(proto, h, p, ssl_handshake_timeout=10)
except ValueError:
await loop.create_connection(proto, h, p, ssl=ssl.create_default_context(),
ssl_handshake_timeout=10) Prevention
- Treat ssl_handshake_timeout as TLS-only config and gate it behind the TLS flag.
- Pop TLS-only keys when downgrading to plaintext: kwargs.pop('ssl_handshake_timeout', None).
- Keep one shared kwargs builder for connections so TLS args cannot leak into plaintext calls.
When it happens
Trigger: Calling loop.create_connection(proto, host, port, ssl_handshake_timeout=10.0) with ssl unset. Typical when a TLS config object is spread into kwargs but its ssl key ended up None/omitted.
Common situations: Shared kwargs dicts for both TLS and plaintext clients; disabling TLS for local testing while leaving the timeout knob in place; refactors that made ssl conditional (**tls_kwargs) without cleaning the timeout.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- ssl_shutdown_timeout is only meaningful with ssl
- server_hostname is only meaningful with ssl
- You must set server_hostname when using ssl without a host
- sslcontext is expected to be an instance of ssl.SSLContext,
- Socket cannot be of type SSLSocket
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/b2fec1cf3f6fd27e.
Report an issue: GitHub.