426 Upgrade Required
The server refuses to perform the request using the current protocol but might be willing to do so after the client upgrades to a different protocol.
Meaning & Description
Common Causes
- Client failed to include the `Connection: Upgrade` and `Upgrade: websocket` headers when accessing a WebSocket route.
- The server configuration enforces a minimum protocol version that the client does not support.
- Reverse proxy misconfiguration stripping out protocol upgrade headers before reaching the backend.
How to fix a 426 error
- Check the `Upgrade` header in the 426 response to identify which protocol the server demands.
- If connecting to a WebSocket, ensure your client library sends `Upgrade: websocket` and `Connection: Upgrade`.
- Verify that your proxy or load balancer (e.g., Nginx, HAProxy) is configured to proxy WebSocket upgrade headers.
- Upgrade your client tool (e.g., curl, browser, HTTP library) to support the requested protocol (like HTTP/2).
Browser & SEO Behaviour
Browser Behavior
If a browser receives a 426 response to a normal navigation request, it will display the response body as an error page. If a WebSocket API (`new WebSocket()`) fails the handshake, it throws a JS error.
SEO Impact
If a crawler attempts to index a page and receives a 426, it will fail to index the content. Ensure standard HTTP GET routes do not strictly demand WebSocket upgrades.
CDN Behavior
CDNs may return 426 if a client tries to communicate over an unsupported legacy protocol, or pass through the backend's 426 if WebSocket upgrade fails.
Code Examples
GET /chat HTTP/1.1
Host: api.example.com
# Missing Upgrade headersapp.get('/chat', (req, res) => {
if (req.headers['upgrade'] !== 'websocket') {
res.set('Upgrade', 'websocket');
res.set('Connection', 'Upgrade');
return res.status(426).send("Upgrade Required: Please use WebSockets.");
}
// Handle WebSocket
});@app.get("/ws-endpoint")
def enforce_websocket(request: Request):
if request.headers.get("upgrade") != "websocket":
headers = {"Upgrade": "websocket", "Connection": "Upgrade"}
raise HTTPException(status_code=426, detail="Upgrade Required", headers=headers)
return {"status": "ok"}func wsHandler(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Upgrade") != "websocket" {
w.Header().Set("Upgrade", "websocket")
w.Header().Set("Connection", "Upgrade")
http.Error(w, "Upgrade Required", 426)
return
}
// Upgrade connection...
}[HttpGet("chat")]
public IActionResult ChatEndpoint() {
if (!HttpContext.WebSockets.IsWebSocketRequest) {
Response.Headers.Add("Upgrade", "websocket");
Response.Headers.Add("Connection", "Upgrade");
return StatusCode(426, "Please connect using WebSockets.");
}
return Ok();
}curl -v http://api.example.com/chat \
-H "Connection: Upgrade" \
-H "Upgrade: websocket"Raw HTTP Response Example
HTTP/1.1 426 Upgrade Required
Connection: Upgrade
Upgrade: websocket
Content-Type: text/plain
Content-Length: 43
This endpoint requires a WebSocket upgrade.Real-world Examples
Frequently Asked Questions
What is the difference between 426 Upgrade Required and 101 Switching Protocols?
426 is an error code indicating the server rejected the request and demands a different protocol. 101 is a successful informational response confirming the server has accepted the client's request to switch protocols.
How do I fix a 426 Upgrade Required error?
Check the `Upgrade` header in the server's response. You must modify your client to send the request using the specified protocol, such as HTTP/2 or WebSockets, along with the appropriate `Upgrade` and `Connection` headers.
Is 426 used to force HTTPS?
While originally intended to allow upgrading from HTTP to TLS (RFC 2817), modern web architecture prefers using 301/302 redirects to HTTPS and enforcing HSTS instead of relying on the 426 Upgrade mechanism.
Why does my WebSocket proxy return 426?
Your reverse proxy (like Nginx) is likely not configured to pass the `Upgrade` and `Connection` headers to the backend. Without those headers, the backend thinks it's a normal HTTP request and returns 426.
Can 426 be cached?
No. Protocol upgrade negotiations are specific to the current TCP connection and cannot be cached for future requests or different clients.
Did You Know?
RFC 2817 originally defined 426 for upgrading plain HTTP connections to TLS across the same port, but this pattern never caught on. Redirects to port 443 became the standard instead.
Today, 426 is almost exclusively seen in the wild when dealing with WebSocket endpoints.
When a server returns 426, it is mandatory to include the 'Upgrade' header to tell the client what protocols are acceptable.
Developer Tips
- When building a WebSocket endpoint, always gracefully handle standard HTTP requests by returning a 426 Upgrade Required with a clear text explanation, rather than just crashing or returning a 400 Bad Request.
- If using Nginx as a proxy for WebSockets, ensure you include `proxy_set_header Upgrade $http_upgrade;` and `proxy_set_header Connection 'upgrade';`.
- Never configure your main homepage or API root to require an upgrade, as this will completely break SEO crawlers and older clients.
Interview Questions
These are questions you might face in a backend or API design interview that touch on HTTP 426.
When is a server most likely to return a 426 Upgrade Required status code?
When a client sends a standard HTTP request to an endpoint that strictly requires a WebSocket connection, or when forcing a shift from HTTP/1.1 to HTTP/2.
Which HTTP header must accompany a 426 response?
The `Upgrade` header must be present, specifying which protocols the server is willing to accept.
Why is 426 not commonly used to force HTTP to HTTPS transitions today?
Because 301/302 redirects to port 443 combined with HSTS (HTTP Strict Transport Security) are universally supported by browsers, simpler to implement, and more secure than in-band protocol upgrades.
Common Interview Mistakes
- Confusing 426 Upgrade Required with requiring a software or app update.
- Thinking 426 is a 5xx server error.
- Failing to mention WebSockets or the mandatory `Upgrade` response header.