Prompt and context
An API gateway requires clients to use HTTP/3 but receives an HTTP/1.1 request. Explain when to return 426, what the response should contain, how a client recovers, and why every protocol mismatch should not become 426.
HTTP 426 means the server refuses to perform the request using the current protocol but might do so after the client upgrades. RFC 9110 gives an example with Upgrade: HTTP/3.0. It is an actionable protocol-upgrade request, not a generic parameter error, a TLS handshake failure, or proof that the server cannot serve the resource at all.
What the interviewer is testing
The interviewer is testing precise 426 semantics, the boundary between the Upgrade field and TLS or HTTP-version negotiation, and your handling of caches, proxies, idempotent retries, telemetry, and client compatibility. You should also distinguish 400, 421, and 505.
Clarifying questions
Confirm whether the upgrade concerns HTTP, the TLS connection, or an application version; whether the client can establish the target protocol; whether the method is safe to retry; whether a proxy sits in front of the gateway; and whether the original request must be sent again. Ask whether some tenants must remain on the old protocol and whether a canary and rollback are required.
30-second answer
“I would return 426 only when the current protocol prevents the server from handling the resource, while a supported target protocol could handle it. The response should include an explicit Upgrade value and a readable or machine-readable explanation. The client must create the target connection before deciding whether to retry; it cannot assume the request did not execute. A fully unsupported HTTP version is 505, a routing mismatch may be 421, and ordinary syntax errors are 400. The gateway should track protocol, proxy chain, upgrade outcomes, cache behavior, and retry amplification.”
Deep-dive answer
Step 1: Confirm the trigger condition
The essential condition is “the current protocol is unsuitable, but an upgrade might succeed.” The server needs a known target protocol and a real upgrade path. Unknown clients, missing fields, and an old application version do not automatically qualify.
Step 2: Make the response actionable
Include an Upgrade field listing a protocol the server accepts, such as HTTP/3.0, plus a short body or machine-readable error code. Do not return only a vague “please upgrade” message or expose internal topology.
HTTP/1.1 426 Upgrade Required
Upgrade: HTTP/3.0
Content-Type: application/problem+json
{"type":"https://example.test/problems/upgrade-required","title":"Upgrade required"}Step 3: Separate connection upgrade from application retry
The client first establishes the target protocol connection and then decides whether to resend the original request. Connection upgrade is a transport or protocol action, not a change to an application field. For a non-idempotent POST, the client needs an idempotency key, execution lookup, and an API-specific retry contract.
Step 4: Keep TLS at the right layer
426 does not replace a TLS handshake or certificate error. RFC 2817 discusses upgrading HTTP/1.1 to TLS, but modern deployments usually negotiate TLS and HTTP versions while establishing the connection. If the request never reaches a stage where an HTTP response can be generated, record a handshake failure instead of fabricating 426.
Step 5: Draw the status-code boundaries
400 means invalid request syntax or content; 421 means the request reached a server that cannot produce a response for that request; 505 means the server does not support the HTTP version used in the request. 426 promises a possible continuation after upgrade, so it should not hide an unavailable target protocol or missing resource.
Step 6: Design proxy, cache, and retry behavior
A proxy may terminate a connection and create another request, while clients may retry automatically. State a deliberate Cache-Control policy so a shared cache does not preserve a migration error indefinitely. Record the original protocol, negotiated result, proxy chain, and retry count. Align retry budgets with rate limits and circuit breakers.
Step 7: Protect canaries and rollback
Canary the clients that can use the target protocol, observe success rate, latency, error type, and duplicate writes, then expand. Keep the old protocol until migration is complete and prepare rollback by client, tenant, or region. A 426 count alone is not proof of success because intermediaries may consume or rewrite the response.
Step 8: Verify client recovery
Test GET, idempotent PUT, non-idempotent POST, long-lived connections, proxy forwarding, cache hits, TLS failures, unknown upgrade values, and an unavailable target protocol. Verify reconnection, duplicate writes, authentication context, and telemetry that separates 426, 421, 505, and handshake failures.
Model answer
I would first verify that the current protocol really blocks handling the resource, while the target protocol is available and has a defined upgrade path. Then I would return 426 with Upgrade: HTTP/3.0 and a machine-readable error, without leaking internal details. The client must establish HTTP/3 and use method idempotency, an idempotency key, and an execution lookup before retrying; it cannot infer that the original write did not happen. TLS handshake failures belong at the connection layer, a completely unsupported HTTP version is 505, a routing mismatch may be 421, and malformed requests are 400. I would canary by client capability, monitor protocol, proxy chain, duplicate writes, and success rate, set cache and retry boundaries, and preserve an old-protocol rollback path. Tests would cover methods, proxies, caches, long connections, and an unavailable target protocol.
Common mistakes
Treating 426 as a generic old-client error
426 is about a protocol upgrade that might let the same resource be served. An old application version, missing field, or denied permission needs its own application contract.
Assuming the Upgrade field performs the upgrade
The response tells the client what to do next; the client still creates a suitable connection. Servers and proxies must support the target protocol, authentication, routing, limits, and telemetry.
Automatically replaying non-idempotent requests
426 can occur near the request-processing boundary. Without an idempotency key or execution lookup, replaying a POST can create duplicate side effects.
Follow-up questions and answers
What is the core difference between 426 and 505?
426 says an upgrade might make the request succeed and points to the target protocol. 505 says the server does not support the HTTP version used by the request and normally makes no upgrade promise.
If an edge proxy terminates HTTP/3, can the origin still return 426?
The edge should handle negotiation and routing at its boundary and pass the needed context to the origin. If the origin cannot see the real client protocol, it should not infer it from connection fields; record proxy protocol and forwarding semantics instead.
Can a 426 response be cached?
Only when the cache key, client capability, and migration plan are explicit. The default should avoid a shared cache preserving a protocol migration error for a long period, with response fields expressing any short policy.
How can a POST safely recover from 426?
Use an idempotency key, an execution-status lookup, and a client retry budget. Establish the target connection first, then confirm whether the original request executed. If it cannot be confirmed, report a pending state instead of blindly replaying.
When should the connection be rejected instead of returning 426?
If TLS, ALPN, or a lower-level protocol negotiation fails before an HTTP response can be produced, close the connection and record the reason. 426 requires a sendable HTTP response and an actionable upgrade suggestion.
How do you prove the migration did not harm users?
Canary by client capability and compare post-426 success, latency, duplicate writes, authentication failures, proxy distribution, and rollback time. Metrics must separate edge, origin, and client retries rather than counting only 426 responses.