aio-libs/aiohttp · error · WSServerHandshakeError
Invalid upgrade header
Error message
Invalid upgrade header
What it means
Raised as `WSServerHandshakeError` (client.py:1101-1108) when the response to a WS upgrade request has an `Upgrade` header whose value (case-insensitive) is not exactly `websocket`. RFC 6455 requires the server to echo `Upgrade: websocket`; a mismatch means the server did not honour the upgrade (e.g., returned a normal HTTP response). Status was 101 but the Upgrade header is wrong/absent.
Source
Thrown at aiohttp/client.py:1102
proxy=proxy,
ssl=ssl,
server_hostname=server_hostname,
proxy_headers=proxy_headers,
)
try:
# check handshake
if resp.status != 101:
raise WSServerHandshakeError(
resp.request_info,
resp.history,
message="Invalid response status",
status=resp.status,
headers=resp.headers,
)
if resp.headers.get(hdrs.UPGRADE, "").lower() != "websocket":
raise WSServerHandshakeError(
resp.request_info,
resp.history,
message="Invalid upgrade header",
status=resp.status,
headers=resp.headers,
)
if not resp._upgraded:
raise WSServerHandshakeError(
resp.request_info,
resp.history,
message="Invalid connection header",
status=resp.status,
headers=resp.headers,
)
# key calculation
r_key = resp.headers.get(hdrs.SEC_WEBSOCKET_ACCEPT, "")View on GitHub (pinned to c0ef574e29)
Solutions
- Inspect `exc.headers` to see the actual Upgrade header value.
- Fix the server/proxy to echo `Upgrade: websocket` on 101 responses.
- Bypass intermediaries (connect directly to the WS server) to isolate where the header is dropped.
- If the server genuinely doesn't support WS, switch to a real WS endpoint.
Example fix
// before
# nginx missing: proxy_set_header Upgrade $http_upgrade;
await session.ws_connect('wss://host/ws')
// after (server-side nginx fix)
# proxy_http_version 1.1;
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection "upgrade"; Defensive patterns
Strategy: try-catch
Try / catch
from aiohttp import WSServerHandshakeError
try:
ws = await session.ws_connect(url)
except WSServerHandshakeError as e:
upg = e.headers.get('Upgrade', '<missing>')
if 'invalid upgrade header' in (e.message or '').lower():
log.error('Upgrade header was: %s', upg)
raise Prevention
- Ensure the server/proxy echoes `Upgrade: websocket` on 101.
- Configure nginx with the Upgrade forwarding directives.
- Bypass the proxy to confirm the backend itself upgrades correctly.
When it happens
Trigger: Server returned 101 but with `Upgrade: h2c` or no Upgrade header; intermediary rewrote the Upgrade header; buggy server that sends 101 for non-WS reasons.
Common situations: Reverse proxy or CDN that returns 101 but strips/alters the Upgrade header; load balancer doing protocol negotiation; misconfigured server framework that doesn't fully implement RFC 6455.
Related errors
- Invalid connection header
- Invalid window size
- Extension for deflate not supported{ext}
- Invalid response status
- Invalid challenge response
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/e467c089f5f61da8.json.
Report an issue: GitHub.