"raise exc from None" interferes with exception chaining
See original GitHub issueChecklist
- The bug is reproducible against the latest release and/or
master
. - There are no similar issues or pull requests to fix it yet.
Describe the bug
Even though I use exception chaining (raise ... from
) in my app, the original exception info gets deleted because Starlette handles exceptions with raise .. from None
at the outer scope.
Here is a MWE:
from starlette.applications import Starlette
from starlette.endpoints import HTTPEndpoint
from starlette.responses import HTMLResponse
from starlette.routing import Route
class TemplateRenderingError(Exception): pass
class Homepage(HTTPEndpoint):
async def get(self, request):
try:
content = '{a}'.format()
except KeyError as e:
raise TemplateRenderingError from e
return HTMLResponse(content)
app = Starlette(debug=True, routes=[
Route('/', Homepage),
])
Run the server, load /
, then look at the console output.
What I expect to get is a chained exception:
ERROR: Exception in ASGI application
Traceback (most recent call last):
File ".\star_bug.py", line 13, in get
content = '{a}'.format()
KeyError: 'a'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "c:\otree\ve-nodj\lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 394, in run_asgi
result = await app(self.scope, self.receive, self.send)
File "c:\otree\ve-nodj\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 45, in __call__
return await self.app(scope, receive, send)
File "c:\otree\ve-nodj\lib\site-packages\starlette\applications.py", line 112, in __call__
await self.middleware_stack(scope, receive, send)
File "c:\otree\ve-nodj\lib\site-packages\starlette\middleware\errors.py", line 184, in __call__
raise exc
File "c:\otree\ve-nodj\lib\site-packages\starlette\middleware\errors.py", line 159, in __call__
await self.app(scope, receive, _send)
File "c:\otree\ve-nodj\lib\site-packages\starlette\exceptions.py", line 84, in __call__
raise exc
File "c:\otree\ve-nodj\lib\site-packages\starlette\exceptions.py", line 71, in __call__
await self.app(scope, receive, sender)
File "c:\otree\ve-nodj\lib\site-packages\starlette\routing.py", line 582, in __call__
await route.handle(scope, receive, send)
File "c:\otree\ve-nodj\lib\site-packages\starlette\routing.py", line 243, in handle
await self.app(scope, receive, send)
File "c:\otree\ve-nodj\lib\site-packages\starlette\endpoints.py", line 30, in dispatch
response = await handler(request)
File ".\star_bug.py", line 15, in get
raise TemplateRenderingError from e
star_bug.TemplateRenderingError
What I get is only the final exception:
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "c:\otree\ve-nodj\lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 394, in run_asgi
result = await app(self.scope, self.receive, self.send)
File "c:\otree\ve-nodj\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 45, in __call__
return await self.app(scope, receive, send)
File "c:\otree\ve-nodj\lib\site-packages\starlette\applications.py", line 112, in __call__
await self.middleware_stack(scope, receive, send)
File "c:\otree\ve-nodj\lib\site-packages\starlette\middleware\errors.py", line 184, in __call__
raise exc
File "c:\otree\ve-nodj\lib\site-packages\starlette\middleware\errors.py", line 159, in __call__
await self.app(scope, receive, _send)
File "c:\otree\ve-nodj\lib\site-packages\starlette\exceptions.py", line 83, in __call__
raise exc from None
File "c:\otree\ve-nodj\lib\site-packages\starlette\exceptions.py", line 71, in __call__
await self.app(scope, receive, sender)
File "c:\otree\ve-nodj\lib\site-packages\starlette\routing.py", line 582, in __call__
await route.handle(scope, receive, send)
File "c:\otree\ve-nodj\lib\site-packages\starlette\routing.py", line 243, in handle
await self.app(scope, receive, send)
File "c:\otree\ve-nodj\lib\site-packages\starlette\endpoints.py", line 30, in dispatch
response = await handler(request)
File ".\star_bug.py", line 15, in get
raise TemplateRenderingError from e
Starlette uses raise exc from None
in 4 places:
ExceptionMiddleware.__call__
ServerErrorMiddleware.__call__
WebSocketEndpoint.dispatch
_ASGIAdapter.send
It seems to me that in all 4 cases the from None
could hide intentional context about users’ errors.
Having the chained traceback would be very valuable both for reading the console output and for programmatic use
(I want to make a middleware that looks at the .__cause__
attribute of certain exceptions to deliver a more relevant error message). I’m happy to provide more details on my use case.
Issue Analytics
- State:
- Created 3 years ago
- Comments:5 (3 by maintainers)
Top GitHub Comments
It’s possible that there might be a good reason for one or more of those cases to be a
raise exc from None
, but in general I’d agree with you, yup. It’s probably worth a pull request, switching the behaviour of those. We can then review each case in that pull request, and check if any of them are “raise from None” for a good reason.Another fix for the issue would be to remove the
from None
in the following 4 places: