Streaming Response suppresses errors #1739
-
When using Streaming response, there is an underlying assumption that the generator (for the stream) will not encounter any errors. In case it does, nothing gets sent back to the client, and an unhandled Runtime error occurs server-side. From starlette/responses.py - line 221: async def stream_response(self, send: Send) -> None:
await send(
{
"type": "http.response.start",
"status": self.status_code,
"headers": self.raw_headers,
}
)
async for chunk in self.body_iterator:
if not isinstance(chunk, bytes):
chunk = chunk.encode(self.charset)
await send({"type": "http.response.body", "body": chunk, "more_body": True})
await send({"type": "http.response.body", "body": b"", "more_body": False}) Notice how we're simply iterating over body_iterator, not handling errors anywhere. I've been able to kind of fix this by changing the code to the following: async def stream_response(self, send: Send) -> None:
await send(
{
"type": "http.response.start",
"status": self.status_code,
"headers": self.raw_headers,
}
)
try:
async for chunk in self.body_iterator:
if not isinstance(chunk, bytes):
chunk = chunk.encode(self.charset)
await send({"type": "http.response.body", "body": chunk, "more_body": True})
except Exception as e:
logging.getLogger("main").error(e)
await send({"type": "http.response.body", "body": b"", "more_body": False})
else:
await send({"type": "http.response.body", "body": b"", "more_body": False}) Now at least I see the error being logged. Should I submit a PR for this? 1- How do you log errors in Starlette normally? 2- How can we communicate this error back to the client? Does it make sense to populate the body with the error? Given that the client is expecting specific chunk formats, seems annoying to throw the responsibility of checking body for errors on them maybe? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 8 replies
-
It does not make sense to populate the body with an error - the client would not know how to check for an error, any already sent |
Beta Was this translation helpful? Give feedback.
Starlette
class as an ASGI app, then the middlewaresExceptionMiddleware
andServerErrorMiddleware
would handle the error:ExceptionMiddleware
would usually transform the response into a 500 response - however, as the response has already started,ExceptionMiddleware
then raises aRuntimeError
instead;ServerErrorMiddleware
would also usually transform the response into a 500 response - but again, as the response has already started, that response is not sent. Then,ServerErrorMiddleware
raises the error again, where it can be logged by the server;Starlette
, you can passexception_handlers
that would be tasked with handling errors raised byServe…