Skip to main content
417

Expectation Failed

Active
RFC 9110 §15.5.18Since 1997Proxies, file upload APIs, legacy HTTP/1.1 servers, curl interactions

HTTP 417 Expectation Failed indicates the server cannot meet the expectation given in the request's Expect header field. Defined in RFC 9110 §15.5.18. In practice this only applies to Expect: 100-continue — no other Expect values are standardized. The server is declining to honor the client's stated expectation.

Description

The 417 Expectation Failed status code means that the expectation indicated by the Expect request-header field could not be met by at least one of the inbound servers. The server is explicitly telling the client: I received your Expect header, I understood it, but I cannot or will not honor it.

In the HTTP/1.1 protocol, the Expect header was designed as a mechanism for clients to check whether a server would accept their request before sending a potentially large body. The only standardized value is '100-continue' — the client says 'I have a body to send, will you accept it?' and waits for a 100 Continue interim response before transmitting. If the server cannot or will not accept the request based on the headers alone, it responds with 417 instead of 100.

In practice, 417 is rarely seen in modern APIs because most HTTP/1.1 servers handle the 100-continue mechanism transparently. The status code becomes relevant when: (a) a proxy strips or cannot forward the Expect header, (b) the server explicitly does not support the 100-continue mechanism, (c) the server has already decided to reject the request based on headers (wrong Content-Type, body too large, missing auth) and signals this before the body is sent, or (d) the client sends a non-standard Expect value the server doesn't recognize.

curl automatically sends Expect: 100-continue for POST bodies larger than 1024 bytes. This is configurable via --expect100-timeout. If a server returns 417, curl will typically retry the request without the Expect header. This behavior has caused confusion when developers test APIs that don't support the mechanism.

The 417 status exists at the intersection of protocol negotiation and request optimization. It's a server saying 'don't bother sending that body' — which is actually a useful optimization when the request would be rejected anyway due to authentication, authorization, or content policy violations detectable from headers alone.

Examples

Client sends large upload with Expect: 100-continue
http
POST /api/uploads HTTP/1.1
Host: api.example.com
Content-Type: application/octet-stream
Content-Length: 52428800
Expect: 100-continue
Authorization: Bearer token123
417 response — server does not support 100-continue
http
HTTP/1.1 417 Expectation Failed
Content-Type: application/json
Content-Length: 128 
{"error": "expectation_failed", "message": "This server does not support the Expect: 100-continue mechanism. Resend without the Expect header."}
Client sends non-standard Expect value
http
PUT /api/documents/99 HTTP/1.1
Host: api.example.com
Content-Type: application/json
Content-Length: 4096
Expect: 200-ok
Authorization: Bearer token456

{"title": "Updated Document", "body": "..."}
417 response — unrecognized expectation
http
HTTP/1.1 417 Expectation Failed
Content-Type: application/json

{"error": "expectation_failed", "message": "The Expect header value '200-ok' is not supported. Only '100-continue' is recognized.", "supported_expectations": ["100-continue"]}
Proxy cannot forward expectation
http
POST /api/data/ingest HTTP/1.1
Host: api.example.com
Content-Type: text/csv
Content-Length: 10485760
Expect: 100-continue
X-Request-ID: req_abc123
417 response — proxy strips Expect header
http
HTTP/1.1 417 Expectation Failed
Content-Type: application/json
Via: 1.1 proxy.internal.net

{"error": "expectation_failed", "message": "The intermediary proxy cannot forward the Expect header to the origin server. Please retry without the Expect header.", "proxy": "proxy.internal.net"}

Edge Cases

  • curl sends Expect: 100-continue automatically for POST/PUT bodies larger than 1024 bytes. If a server returns 417, curl retries without the header — this can cause double requests and confusing logs.
  • Some reverse proxies (older nginx, HAProxy configurations) strip the Expect header before forwarding, then return 417 if the backend requires the 100-continue handshake. The fix is proxy-level configuration, not client-side.
  • HTTP/2 and HTTP/3 do not use the Expect: 100-continue mechanism — it's a purely HTTP/1.1 concept. Clients should never send Expect headers over h2/h3 connections.
  • A server that returns 417 MUST NOT have already sent a 100 Continue response for the same request. If it sent 100, it committed to accepting the body — 417 after 100 is a protocol violation.
  • Some servers return 417 when the Content-Length exceeds their configured maximum, using it as an early rejection before body transmission. Technically 413 Payload Too Large is more appropriate, but 417 is used because the rejection happens during the expect negotiation phase.
  • Load balancers that buffer requests may absorb the Expect header and never forward it, making the 100-continue mechanism invisible to the backend. The client receives 200 directly, not 100 then 200.
  • AWS API Gateway and some cloud proxies do not support Expect: 100-continue and may return 417 or silently ignore the header. SDKs that rely on the mechanism need workarounds for these environments.

When You'll See This

  • curl sending a large POST body hits a server that doesn't support 100-continue
  • An HTTP client library sends Expect: 100-continue through a proxy that strips it
  • A file upload service rejects the request early because authentication failed during the expect phase
  • A client sends a non-standard Expect header value the server doesn't recognize
  • Legacy Java HttpURLConnection sends Expect: 100-continue to a modern serverless endpoint that doesn't implement it
  • An IoT device with limited bandwidth uses 100-continue to avoid sending payloads that will be rejected, but the gateway doesn't support it
  • A batch import client sends Expect: 100-continue for a 50MB CSV upload, and the server's max body size is 10MB

Implementation References

LanguageConstant
Gohttp.StatusExpectationFailed
Rusthttp::StatusCode::EXPECTATION_FAILED
Pythonhttp.HTTPStatus.EXPECTATION_FAILED
Node.jshttp.STATUS_CODES[417]
.NETHttpStatusCode.ExpectationFailed
JavaHttpURLConnection.HTTP_EXPECT_FAILED
PHPResponse::HTTP_EXPECTATION_FAILED (Symfony)
Ruby:expectation_failed (Rack)

History

Introduced in HTTP/1.1 (RFC 2068, January 1997) alongside the Expect header mechanism. Refined in RFC 2616 (June 1999) which clarified proxy behavior. Consolidated in RFC 9110 (June 2022, §15.5.18) as part of the HTTP semantics specification rewrite. The status code remains active but is increasingly irrelevant as HTTP/2 and HTTP/3 deprecate the 100-continue mechanism entirely.

Related Status Codes

Related Headers

FAQ

When does HTTP 417 Expectation Failed actually occur in practice?

In modern web development, 417 is rare. The most common trigger is curl sending Expect: 100-continue automatically for POST bodies larger than 1024 bytes to a server that doesn't support the mechanism. You'll also see it when proxies strip the Expect header, when serverless platforms (AWS Lambda, Cloudflare Workers) don't implement 100-continue, or when legacy clients send the header through infrastructure that wasn't designed for it. Most HTTP libraries handle it transparently by retrying without the header.

How should I handle 417 in my API client code?

The standard approach is to retry the request without the Expect header. Most HTTP libraries do this automatically (curl retries, Python requests doesn't send Expect by default, Go's net/http handles it internally). If you're building a custom client: catch 417, remove the Expect header, and resend. For high-throughput systems, disable the Expect: 100-continue mechanism entirely to avoid the extra round-trip — the bandwidth savings only matter for requests that would be rejected, which should be rare in well-designed systems.

What's the difference between 417 Expectation Failed and 100 Continue?

They're two sides of the same mechanism. When a client sends Expect: 100-continue, the server has three choices: (1) send 100 Continue — meaning 'go ahead, send the body', (2) send 417 Expectation Failed — meaning 'don't bother sending the body, I can't honor your expectation', or (3) send a final status like 401 or 413 — meaning 'I'm rejecting this request outright based on your headers'. 417 specifically means the Expect header itself cannot be honored, while other 4xx codes mean the request fails for a different reason.