HTTP 417 Expectation Failed
HTTP 417 Expectation Failed means the server cannot satisfy the requirement stated in the client’s Expect request header. In practice, this almost exclusively means the server does not support or refuses the Expect: 100-continue handshake. The client asked the server to confirm it would accept a request before the body was sent; the server is responding that it cannot make that commitment.
Quick reference
| Code | 417 |
|---|---|
| Name | Expectation Failed |
| Category | 4xx Client Error |
| Specification | RFC 9110 §15.5.18 |
| Triggered by | Expect request header the server cannot fulfill |
| Fix | Remove or disable the Expect header |
| Cacheable? | No |
The Expect: 100-continue mechanism
RFC 9110 defines the Expect header for a single registered token: 100-continue. The mechanism works like this:
POST /upload HTTP/1.1 Host: api.example.com Content-Type: application/json Content-Length: 524288 Expect: 100-continue <client pauses, waits for 100> HTTP/1.1 100 Continue <client now sends body> POST body (524288 bytes)... HTTP/1.1 201 Created
The client sends headers first, then waits for the server to respond. If the server responds with 100 Continue, the client sends the body. If the server responds with an error (401, 403, 413, etc.), the client abandons the body without wasting bandwidth uploading it. This saves time and bandwidth for large requests that might be rejected.
When the server cannot implement this handshake at all — it does not support the Expect header mechanism — it returns 417. The client should interpret 417 as: “send the body directly, do not wait for a 100.”
Why 417 occurs
Legacy HTTP/1.0 servers: The Expect header was introduced in HTTP/1.1. HTTP/1.0 servers do not understand it. A server stuck on HTTP/1.0 semantics will return 417 when it receives an Expect header it does not know how to handle.
Proxies that strip or mishandle Expect: Some reverse proxies and load balancers do not forward the Expect header to the origin server. Instead, they either strip it silently or return 417 themselves. If 417 appears only when traffic passes through a specific proxy tier, the proxy is the source.
Servers that explicitly disable 100-continue: Some server configurations or middleware explicitly disable the 100-continue mechanism and return 417 for any request that uses it. This is uncommon but exists in certain embedded or constrained server environments.
Non-standard Expect values: RFC 9110 defines only 100-continue as a valid Expect token. A client sending any other Expect value should receive 417 from a conforming server, because the server does not recognize the expectation.
HTTP client libraries and Expect headers
Many HTTP client libraries automatically add Expect: 100-continue for POST and PUT requests above a size threshold (commonly 1MB or a configurable limit). This happens transparently and developers may not realize the header is being sent. When the server returns 417, the developer sees the error without having explicitly written Expect: 100-continue in their code.
How to disable automatic Expect headers in common clients:
Python requests:
import requests
response = requests.post(
url,
data=body,
headers={'Expect': ''} # Empty string removes the header
)
curl:
# curl adds Expect: 100-continue for bodies over 1024 bytes # Disable with an empty Expect header: curl -H 'Expect:' -X POST -d @large_file.json https://api.example.com/upload
Java HttpClient (java.net.http):
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Expect", "") // Suppress 100-continue
.POST(HttpRequest.BodyPublishers.ofFile(path))
.build();
Go net/http: Go’s HTTP client does not add Expect: 100-continue by default. If a 417 appears from Go, check for middleware or custom transport layers adding the header.
Server-side handling
If your server is returning 417 and clients are failing, you have two options: implement 100-continue support, or document that clients should not use the Expect header.
nginx supports 100-continue natively for upstream connections. The proxy_expect_100_continue directive (default: on) controls whether nginx forwards the Expect header to upstream. If 417 is coming from nginx itself, ensure proxy_pass is configured correctly.
Express.js: Node.js HTTP server handles Expect: 100-continue by default. To explicitly reject it:
server.on('checkContinue', (req, res) => {
// Return 417 to reject Expect: 100-continue
res.writeHead(417);
res.end();
});
To accept it (default behavior, useful to be explicit):
server.on('checkContinue', (req, res) => {
res.writeContinue();
// Then handle the request normally
app(req, res);
});
417 vs related codes
| Code | Meaning | Cause |
|---|---|---|
| 100 | Continue | Server accepts Expect: 100-continue, client should send body |
| 417 | Expectation Failed | Server cannot fulfill Expect header, client should retry without it |
| 413 | Content Too Large | Body would be too large (returned instead of 100 when server checks Content-Length) |
| 400 | Bad Request | Malformed Expect header value |
Frequently asked questions
What does HTTP 417 mean?
The server cannot satisfy the requirement in the Expect request header. In practice, this almost always means the server does not support the Expect: 100-continue handshake. Remove or disable the Expect header in the client and retry.
Why is my HTTP library sending Expect: 100-continue without me asking?
Many HTTP client libraries automatically add Expect: 100-continue for large request bodies. This is a performance optimization that saves bandwidth when requests might be rejected. It is correct behavior but can cause 417 with servers that do not support the mechanism. Disable it with an empty Expect: header override.
Is HTTP 417 retryable?
Yes. Retry the request without the Expect header (or with an empty Expect value to suppress it). The server is not rejecting the request content — it is rejecting the handshake mechanism. The same request body will likely succeed without the Expect header.
What is the difference between 417 and 428?
417 means the client’s Expect header cannot be satisfied. 428 means the client did not include a required conditional header (like If-Match) that the server requires. Both are 4xx errors caused by missing or unsatisfiable headers, but they are about different headers in different contexts.
Related guides
HTTP 100 Continue · HTTP 428 Precondition Required · HTTP 413 Content Too Large
Standards reference
Definitions from the IANA HTTP Status Code Registry and RFC 9110 §15.5.18. Human-readable guidance by ErrorLookup. · HTTP 417 quick reference →