python/cpython · error · ValueError
You must set server_hostname when using ssl without a host
Error message
You must set server_hostname when using ssl without a host
What it means
Raised by create_connection when ssl is enabled but no host name is available to use as the TLS server_hostname. When server_hostname is omitted, asyncio defaults it to `host`; if host is empty/None (typical when connecting via a pre-made socket or only a port), certificate verification has nothing to verify against, so it refuses. Passing server_hostname='' explicitly bypasses the hostname check.
Source
Thrown at Lib/asyncio/base_events.py:1101
connection in the background. When successful, the coroutine
returns a (transport, protocol) pair.
"""
if server_hostname is not None and not ssl:
raise ValueError('server_hostname is only meaningful with ssl')
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
View on GitHub (pinned to bc6749cc3b)
Solutions
- Pass server_hostname explicitly: create_connection(proto, None, None, sock=s, ssl=ctx, server_hostname='example.com').
- If you deliberately want no hostname verification (rare, insecure), pass server_hostname=''.
- Otherwise supply host (and port) instead of a raw socket so asyncio can derive the name.
Example fix
// before
transport, proto = await loop.create_connection(
factory, None, None, sock=raw_sock, ssl=ctx) # ValueError
// after
transport, proto = await loop.create_connection(
factory, None, None, sock=raw_sock, ssl=ctx,
server_hostname='api.example.com') Defensive patterns
Strategy: validation
Validate before calling
if ssl_ctx is not None and not host and not server_hostname:
raise ConfigError('server_hostname required when using ssl without a host') Try / catch
try:
tp, pr = await loop.create_connection(proto, None, None, sock=s, ssl=ctx)
except ValueError as e:
if 'server_hostname' not in str(e):
raise
tp, pr = await loop.create_connection(proto, None, None, sock=s, ssl=ctx,
server_hostname=expected_name) Prevention
- When adopting raw sockets for TLS, always carry the intended peer name alongside the socket.
- Never pass empty host '' with ssl unless you also set server_hostname explicitly.
- Encapsulate socket+ssl+hostname in one connection-spec object so they travel together.
When it happens
Trigger: Calling create_connection(proto, None, None, sock=s, ssl=ctx) — an already-connected socket with TLS but no server_hostname. Also create_connection(proto, '', 443, ssl=ctx).
Common situations: Wrapping an already-accepted/tunnelled socket (e.g. from a proxy CONNECT or a test harness) in TLS without naming the target; migrating code that used loop.sock_connect + manual SSL transport.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- server_hostname is only meaningful with ssl
- ssl_handshake_timeout is only meaningful with ssl
- ssl_shutdown_timeout is only meaningful with ssl
- 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/68a80e14d98026e0.
Report an issue: GitHub.