Repository navigation
Sentry removes chained exceptions during ASGI application crash #5624
Description
How do you use Sentry?
Sentry Saas (sentry.io)
Version
2.35.0
Steps to Reproduce
We have an ASGI application; we use Sentry in it, by way of calling sentry_sdk.init.
We recently had a incident; during that incident, the ASGI application was crashing. Our logs contained:
2026-03-03 16:59:59,994 - uvicorn.error - ERROR - Exception in ASGI application
Traceback (most recent call last):
File "/…/.venv/lib/python3.10/site-packages/uvicorn/protocols/http/h11_impl.py", line 366, in run_asgi
result = await app(self.scope, self.receive, self.send)
[snipped]
File "/…/.venv/lib/python3.10/site-packages/sentry_sdk/integrations/starlette.py", line 408, in _sentry_patched_asgi_app
return await middleware(scope, receive, send)
File "/…/.venv/lib/python3.10/site-packages/sentry_sdk/integrations/asgi.py", line 179, in _run_asgi3
return await self._run_app(scope, receive, send, asgi_version=3)
File "/…/.venv/lib/python3.10/site-packages/sentry_sdk/integrations/asgi.py", line 268, in _run_app
raise exc from None
File "/…/.venv/lib/python3.10/site-packages/sentry_sdk/integrations/asgi.py", line 263, in _run_app
return await self.app(
File "/…/.venv/lib/python3.10/site-packages/starlette/applications.py", line 113, in __call__
await self.middleware_stack(scope, receive, send)
File "/…/.venv/lib/python3.10/site-packages/sentry_sdk/integrations/starlette.py", line 150, in _create_span_call
return await old_call(app, scope, receive, send, **kwargs)
[snip more frames]
File "/…/app/middleware/authorization_middleware.py", line 79, in __call__
verifier.verify(token, request)
File "/…/app/token_verifier.py", line 72, in verify
raise HTTPException(
starlette.exceptions.HTTPException: 401: Failed to Authorize"
Now, that exception is a bug; I think we're supposed to return a 401 response, not raise.
But what hampered us during this incident is that line 72 there is:
except Exception as e:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Failed to Authorize",
headers={"WWW-Authenticate": "Bearer"},
) from e
(Note that this is still our code.) Note the from e: there should be an additional exception's worth of stack frames, but the stack trace above terminated there. That is, from e should normally look something like this:
Traceback (most recent call last):
[snip]
RuntimeError: I couldn't do it.
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
[snip]
raise RuntimeError("ouch") from e
RuntimeError: ouch
Having the first bit (this exception led to the second exception) would have really helped us in the incident.
By default, FastAPI / Uvicorn will emit that "The above exception was …" bit automatically. In fact, I copy/pasted that snippet from a test FastAPI app. So, in a small test, it works; in our production code, not so much.
This frame in Sentry's code, I think, is why we do not, in prod, get chained exceptions in the backtrace:
File "/…/.venv/lib/python3.10/site-packages/sentry_sdk/integrations/asgi.py", line 268, in _run_app
raise exc from None
That code is here.
That from None removes the context/exception cause from the exception. There does not seem to be a reason for that in the linked code; this means we lose the context from the exception in our logs.
There is also this line, and I think both from Nones are incorrect.
Sentry should re-propagate the current exception with whatever __context__/__cause__ is has. A simple raise (without "exc") is sufficient.
See Exception Chaining in the Python docs for more information.
Expected Result
Sentry does not de-chain exceptions during an ASGI crash
Actual Result
Sentry de-chains the exception, resulting in our logging library not logging a full stack trace.
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsNo status
Activity
linear-code commentedon Mar 10, 2026
PY-2128
sentrivana commentedon Mar 10, 2026
Hey @roy-work, thanks for taking the time to write a great bug report, it's appreciated.
I'm unsure why we chose to
raise from Nonein the ASGI integration (or anywhere in the SDK, for that matter), but since we've had support for reporting exception groups/chained exceptions for a while now, I believe it might just be an artifact of the past. We'll investigate.Just re-raise the original exception, as-is
alexander-alderman-webb commentedon Mar 19, 2026
Thanks @roy-work for the accurate investigation and good report!
Removing
from Noneon master would result in many new issues in Sentry for users who upgrade to a new minor SDK version.For this reason we will make the change with the next major. See the PR: #5709
fix: Do not raise from None (#5709)
roy-work commentedon Mar 19, 2026
To be perfectly honest, that seems a bit like a spacebar heater. Can I ask why you think users are dependent on broken stacktraces?
… regardless, … maybe my org can work with that. It looks like a few alpha versions of 3.0 were released to PyPI, but there hasn't been one since October. I'm curious when there might be another? (I'm wondering if maybe we can tolerate a 3.0a version, until such a time as 3.0 is released for real.)
sentrivana commentedon Mar 20, 2026
We consider changes in the SDK that affect issue grouping in Sentry breaking since folks might have different workflows, alerts, dashboards set up with the assumption that errors are reported a certain way. The stability is important in order for us to provide a consistent experience. So while I get your point, the potential for breaking users is high, especially since we're talking about a fundamental integration like ASGI.
The next major will realistically take a couple more months. The existing alpha releases are from a previous 3.0 branch that we've since abandoned.
I guess we could release a small alpha from the new 3.0 branch with the
from Nonefix, but tbh I don't think that's a good idea as you'd be left behind main -- the 3.0 branch is not being worked on actively at the moment, so there won't be regular releases from it to keep it in sync with fixes and features from main.Let me think about this a bit more and come back to you.
sentrivana commentedon Mar 20, 2026
We'll add an experimental option in the next release (out in the next two weeks) that you can use to disable the behavior and just use a bare
raise:The plan is to still make this the default in the next major, but this way you can enable it early. We'd be happy to know how it's working for your org once you've enabled it if you feel like sharing.
roy-work commentedon Mar 23, 2026
Hmm. I was not thinking that this change should affect issue grouping; I was thinking this is after Sentry already had whatever data that it was going to capture & upload. (I.e., that we're merely changing the exception's backtrace to the frames up the ASGI middleware stack.)
Thank you, that can work, I think.
sentrivana commentedon Mar 24, 2026
We tested the change and it did result in the error being sorted into its own new group. I'm not 100% up to date with the categorization logic on the server but I do believe it takes the stacktrace into account.
In any case, new release with the experimental option is coming later today.