Skip to content

fix(Litestar): Apply failed_request_status_codes to exceptions raised in middleware #4074

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 22 commits into
base: master
Choose a base branch
from

Conversation

vrslev
Copy link
Contributor

@vrslev vrslev commented Feb 19, 2025

This is a fix for #4021: exceptions raised in middleware were sent without taking into account failed_request_status_codes value.

See the test case for an example.


Thank you for contributing to sentry-python! Please add tests to validate your changes, and lint your code using tox -e linters.

Running the test suite on your PR might require maintainer approval. The AWS Lambda tests additionally require a maintainer to add a special label, and they will fail until this label is added.

@vrslev vrslev marked this pull request as ready for review February 19, 2025 08:43
Copy link

codecov bot commented Feb 19, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 80.66%. Comparing base (c2d5a76) to head (c26763f).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4074      +/-   ##
==========================================
- Coverage   80.67%   80.66%   -0.01%     
==========================================
  Files         142      142              
  Lines       15982    15988       +6     
  Branches     2729     2729              
==========================================
+ Hits        12893    12897       +4     
  Misses       2232     2232              
- Partials      857      859       +2     
Files with missing lines Coverage Δ
sentry_sdk/integrations/asgi.py 86.30% <100.00%> (+0.38%) ⬆️
sentry_sdk/integrations/litestar.py 84.86% <100.00%> (+0.20%) ⬆️

... and 3 files with indirect coverage changes

@vrslev
Copy link
Contributor Author

vrslev commented Feb 20, 2025

Relates to #3134

@vrslev
Copy link
Contributor Author

vrslev commented Mar 10, 2025

@sentrivana @antonpirker @untitaker can you review this please? 🙂

@antonpirker antonpirker requested a review from a team as a code owner March 27, 2025 09:42
Copy link
Member

@szokeasaurusrex szokeasaurusrex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the contribution! I need some extra clarification on some items and also have some suggestions, please see the comments I left

@@ -57,17 +57,6 @@
TRANSACTION_STYLE_VALUES = ("endpoint", "url")


def _capture_exception(exc, mechanism_type="asgi"):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to keep this function the same, as a standalone function instead of a method. I don't think it has to be modified to implement your changes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Comment on lines 146 to 150
def _capture_lifespan_exception(self, exc):
# type: (Exception) -> None
return self._capture_exception(exc)

def _capture_request_exception(self, exc):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a bit unsure of the difference between these two functions. Please add docstrings to both to clarify the distinction

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Comment on lines 90 to 92
def _capture_request_exception(self, exc):
# type: (Exception) -> None
"""Ignore exceptions for requests here: we catch them in Litestar.after_exception handler."""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am slightly unsure why this function is needed/how it relates to what you are trying to explain in this PR. Could you please explain in a bit more detail?

Also, I think you need a pass here:

Suggested change
def _capture_request_exception(self, exc):
# type: (Exception) -> None
"""Ignore exceptions for requests here: we catch them in Litestar.after_exception handler."""
def _capture_request_exception(self, exc):
# type: (Exception) -> None
"""Ignore exceptions for requests here: we catch them in Litestar.after_exception handler."""
pass

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, Litestar integration catches exceptions raised in middleware twice:

  1. In the custom ASGI handler.
  2. In the Litestar.after_exception handler, which is added in patch_app_init.

The custom ASGI handler doesn't filter exceptions using failed_request_status_codes, so all exceptions (including those not filtered by the expected status code) appear in Sentry.

Interestingly, this behavior doesn't apply to exceptions raised in request handlers because Litestar prepends the built-in exception handling middleware.


This leads us to the conclusion that the ASGI handler only catches exceptions raised in middleware or lifespan handlers. It's still valuable to catch exceptions from lifespan handlers.

In this case, we patch _capture_request_exception to prevent catching exceptions raised in middleware.

@vrslev vrslev requested a review from a team as a code owner April 1, 2025 14:51
@vrslev vrslev requested a review from szokeasaurusrex April 1, 2025 14:52
Copy link
Member

@szokeasaurusrex szokeasaurusrex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @vrslev, apologies that this review took awhile for me to get around to.

Thanks for making the changes I requested and for explaining the two separate functions. These changes look good for the most part; however, before merging, I'd like us to add tests which ensure that any middleware exceptions which are not HttpExceptions are still captured by the Litestar integration even after these changes.

# type: (Exception) -> None
"""Avoid catching exceptions from request handlers.

Those exceptions are already han in Litestar.after_exception handler.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Those exceptions are already han in Litestar.after_exception handler.
Those exceptions are already handled in Litestar.after_exception handler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@vrslev
Copy link
Contributor Author

vrslev commented Jun 3, 2025

Hey @szokeasaurusrex, I've added the test you asked for :)

@vrslev vrslev requested a review from szokeasaurusrex June 3, 2025 16:08
Copy link
Member

@szokeasaurusrex szokeasaurusrex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, but I'd like a secondary review from someone else on the team before we merge

except RuntimeError:
pass

assert len(events) == 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd consider also asserting that the event is as expected (i.e. it is a runtime error with the message "Too Hot")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. I’ll add it tomorrow 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@vrslev vrslev requested a review from szokeasaurusrex June 3, 2025 19:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants