aio-libs/aiohttp · warning · HTTPExpectationFailed
Unknown Expect: %s
Error message
Unknown Expect: %s
What it means
The default Expect-header handler (_default_expect_handler) is invoked when a request carries an Expect header. For HTTP/1.1, the only recognized value is '100-continue' (case-insensitive), to which the server responds with an interim 'HTTP/1.1 100 Continue'. Any other Expect value (e.g. a future or custom expectation token) raises HTTPExpectationFailed (HTTP 417), because the server cannot satisfy an unknown expectation and per RFC 7231 must reject the request.
Source
Thrown at aiohttp/web_urldispatcher.py:305
def __repr__(self) -> str:
return f"<MatchInfoError {self._exception.status}: {self._exception.reason}>"
async def _default_expect_handler(request: Request) -> None:
"""Default handler for Expect header.
Just send "100 Continue" to client.
raise HTTPExpectationFailed if value of header is not "100-continue"
"""
expect = request.headers.get(hdrs.EXPECT, "")
if request.version == HttpVersion11:
if expect.lower() == "100-continue":
await request.writer.write(b"HTTP/1.1 100 Continue\r\n\r\n")
# Reset output_size as we haven't started the main body yet.
request.writer.output_size = 0
else:
raise HTTPExpectationFailed(text="Unknown Expect: %s" % expect)
class Resource(AbstractResource):
def __init__(self, *, name: str | None = None) -> None:
super().__init__(name=name)
self._routes: dict[str, ResourceRoute] = {}
self._any_route: ResourceRoute | None = None
self._allowed_methods: set[str] = set()
def add_route(
self,
method: str,
handler: type[AbstractView] | Handler,
*,
expect_handler: _ExpectHandler | None = None,
) -> "ResourceRoute":
if route := self._routes.get(method, self._any_route):
raise RuntimeError(View on GitHub (pinned to d041d4d0fd)
Solutions
- Have the client send only 'Expect: 100-continue' (the RFC-defined expectation) or omit the header.
- If a custom expectation is needed, register a custom expect_handler on the route via expect_handler=<async fn> that handles your token.
- Return a clear 417 response to the client and document the unsupported expectation.
Example fix
// before (client)
headers = {'Expect': '102-processing'}
// after
headers = {'Expect': '100-continue'} # or omit the header Defensive patterns
Strategy: try-catch
Try / catch
from aiohttp.web_exceptions import HTTPExpectationFailed
async def handler(request):
try:
...
except HTTPExpectationFailed:
return web.Response(status=417, text='Unsupported Expect header') Prevention
- Register a custom expect_handler on routes where clients send non-standard Expect values.
- Document to clients that only Expect: 100-continue is supported.
- Log the offending Expect value to identify misbehaving clients.
When it happens
Trigger: A client sends an HTTP/1.1 request with an Expect header whose value is not '100-continue' — for example 'Expect: 102-processing', a custom token, or a malformed value. The error is raised during request handling, after the request line and headers are parsed and the route is dispatched, when aiohttp invokes the expect_handler.
Common situations: Non-compliant or experimental clients; testing tools that inject arbitrary Expect values; a client library that sends a newer expectation token the server does not yet support; proxy chaining that mangles the header.
Related errors
- Malformed Digest auth challenge: Missing 'realm' parameter
- Malformed Digest auth challenge: Missing 'nonce' parameter
- Security issue: Digest auth challenge contains empty 'nonce'
- Digest auth error: Unsupported Quality of Protection (qop) v
- Digest auth error: Unsupported hash algorithm: {algorithm}.
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/b06931a2f5054117.
Report an issue: GitHub.