You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I think this is worth as an issue/bug in Starlette, and I'm gonna work on it.
Description
When a Starlette application sends a response with a status code that would have no content, e.g. 204, 304, but the response actually has content, it is accepted by Starlette as valid, the code looks valid, and there's no exception raised by Starlette, it sends the response ASGI message to the server like that.
But Uvicorn takes that as an erroneous message and raises an error of:
RuntimeError: Response content longer than Content-Length
So, an application and code that would look fine in Starlette, and Starlette would accept as valid, results in an error in Uvicorn.
This means that Starlette is accepting some code from the user as valid, but sending an invalid message to Uvicorn.
Minimal Example
Here's a minimal example to reproduce the issue with Starlette:
The problem is even more notorious when using FastAPI, as the same response from above is generated automatically because a function implicitly always returns None if nothing else is returned, and FastAPI will use a JSONResponse by default, so it will try to send the JSON string "null":
fromfastapiimportFastAPIapp=FastAPI()
@app.get("/", status_code=204)defendpoint():
print("Oh, hi mark")
On Uvicorn
Uvicorn checks if there's a content-length header and uses it to set the expected_content_length, if there's none, it is not modified and keeps its default of 0.
So, from Uvicorn's point of view, Starlette is sending a bogus message.
Next steps
I think this has to be solved on Starlette, not on Uvicorn.
I think the sensible thing would be to remove the body of a request with a status code that doesn't contain a body, Uvicorn won't send that body either way, it will just error out.
Another option is to raise an exception to tell the user that they can't provide a body for a status code that doesn't contain a body, but it should be done in Starlette, not in Uvicorn. And if that was the approach chosen, then it would make sense to add a lot of typing @overloads to the __init__ methods of the request classes with the Literal for each status code that would raise an error, and making the content as exclusively None in those overloads, to make those errors show up when editing and checking the code, not only at runtime (in production 😱). This second option would be a lot more code and it wouldn't solve the problem for FastAPI, I would still have to do the first option above in FastAPI.
The text was updated successfully, but these errors were encountered:
Related discussion
I think this is worth as an issue/bug in Starlette, and I'm gonna work on it.
Description
When a Starlette application sends a response with a status code that would have no content, e.g. 204, 304, but the response actually has content, it is accepted by Starlette as valid, the code looks valid, and there's no exception raised by Starlette, it sends the response ASGI message to the server like that.
But Uvicorn takes that as an erroneous message and raises an error of:
So, an application and code that would look fine in Starlette, and Starlette would accept as valid, results in an error in Uvicorn.
This means that Starlette is accepting some code from the user as valid, but sending an invalid message to Uvicorn.
Minimal Example
Here's a minimal example to reproduce the issue with Starlette:
Then call the endpoint, e.g.:
$ curl localhost:8000
The problem is even more notorious when using FastAPI, as the same response from above is generated automatically because a function implicitly always returns
None
if nothing else is returned, and FastAPI will use aJSONResponse
by default, so it will try to send the JSON string"null"
:On Uvicorn
Uvicorn checks if there's a
content-length
header and uses it to set theexpected_content_length
, if there's none, it is not modified and keeps its default of0
.Then that default of
0
forexpected_content_length
is checked here, and that's where the error is raised: https://github.com/encode/uvicorn/blob/fd4386fefb8fe8a4568831a7d8b2930d5fb61455/uvicorn/protocols/http/httptools_impl.py#L532-L533The only case where that is not affected is when
chunked_encoding
is used. And that is used by default when thecontent-length
is not set only if the status code is not one of the status codes without body: https://github.com/encode/uvicorn/blob/fd4386fefb8fe8a4568831a7d8b2930d5fb61455/uvicorn/protocols/http/httptools_impl.py#L498-L505So, from Uvicorn's point of view, Starlette is sending a bogus message.
Next steps
I think this has to be solved on Starlette, not on Uvicorn.
I think the sensible thing would be to remove the body of a request with a status code that doesn't contain a body, Uvicorn won't send that body either way, it will just error out.
Another option is to raise an exception to tell the user that they can't provide a body for a status code that doesn't contain a body, but it should be done in Starlette, not in Uvicorn. And if that was the approach chosen, then it would make sense to add a lot of typing
@overload
s to the__init__
methods of the request classes with theLiteral
for each status code that would raise an error, and making thecontent
as exclusivelyNone
in those overloads, to make those errors show up when editing and checking the code, not only at runtime (in production 😱). This second option would be a lot more code and it wouldn't solve the problem for FastAPI, I would still have to do the first option above in FastAPI.The text was updated successfully, but these errors were encountered: