Comments (5)
Hi @Audiopolis, I attempted to reproduce your issue using this code, but I did not observe the error message that you reported.
Can you please clarify how exactly you encountered this issue? If possible, please share a reproduction with me (you can also do so by opening a PR on my reproduction repo and sharing a link to the PR here).
from sentry-python.
@szokeasaurusrex Thanks for trying. I will try to create a reproduction. In the meantime, I'll clarify how I encountered the issue:
We send an email from a Django view using Resend. In this environment, Resend does not recognize the domain, so it throws an error. We catch that error and use logger.exception(...)
instead, where logger = logging.getLogger(__name__)
. The view returns a 201 response. Then, the exact traceback I added to this issue description is printed.
The original request is automatically converted from an ASGIRequest
(no data
attribute, and can only read body once) to a RES framework Request
(has a cached data
property) by REST framework. I don't know how Sentry gets the original ASGIRequest instead of the DRF Request, but since it does, it makes sense that 'ASGIRequest' object has no attribute 'data'
and You cannot access body after reading from request's data stream
. I will have to analyze the situation more closely and provide a reproduction.
from sentry-python.
Same error is also happening inside Sentry with SDK 2.1.1:
File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/django/__init__.py", line 555, in parsed_body
return self.request.data
^^^^^^^^^^^^^^^^^
AttributeError: 'WSGIRequest' object has no attribute 'data'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/django/__init__.py", line 486, in wsgi_request_event_processor
DjangoRequestExtractor(request).extract_into_event(event)
File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/_wsgi_common.py", line 96, in extract_into_event
parsed_body = self.parsed_body()
^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/django/__init__.py", line 557, in parsed_body
return RequestExtractor.parsed_body(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/_wsgi_common.py", line 142, in parsed_body
return self.json()
^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/_wsgi_common.py", line 154, in json
raw_data = self.raw_data()
^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/django/__init__.py", line 538, in raw_data
return self.request.body
^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/http/request.py", line 328, in body
raise RawPostDataException(
django.http.request.RawPostDataException: You cannot access body after reading from request's data stream", "level":"error", "name":"sentry_sdk.errors"}
Can be seen here: https://cloudlogging.app.goo.gl/yfAdqBdmA8iER8ZQ8 (retricted link)
from sentry-python.
So just to expand on what was already written here, the way DRF works is that it wraps the native Django WSGIRequest
(or ASGIRequest
) in its own Request
. The wrapper class adds some stuff on top and proxies everything else to the underlying Django request.
We capture the data here. Basically, self.request.data
is only expected to be there if this is a DRF Request
; otherwise we essentially fall back to self.request.body
(that's what RequestExtractor.parsed_body(self)
eventually looks at). Reading the body
on a Django request should be fine but in some cases the body has already started being read and we hit this.
The quick "fix" would be to capture RawPostDataException
when we try to access request.body
and just give up on reading the body ourselves and return None
. However this doesn't address the underlying problem of why request.data
is not there in the first place (it indeed looks like we're working with the Django request instead of the DRF one).
Wasn't able to repro this yet -- @Audiopolis What does the request look like in your app? I assume it's a POST? Does it contain any form data, uploaded files, etc.? Do you access anything on the request in the view?
from sentry-python.
So just to expand on what was already written here, the way DRF works is that it wraps the native Django
WSGIRequest
(orASGIRequest
) in its ownRequest
. The wrapper class adds some stuff on top and proxies everything else to the underlying Django request.We capture the data here. Basically,
self.request.data
is only expected to be there if this is a DRFRequest
; otherwise we essentially fall back toself.request.body
(that's whatRequestExtractor.parsed_body(self)
eventually looks at). Reading thebody
on a Django request should be fine but in some cases the body has already started being read and we hit this.The quick "fix" would be to capture
RawPostDataException
when we try to accessrequest.body
and just give up on reading the body ourselves and returnNone
. However this doesn't address the underlying problem of whyrequest.data
is not there in the first place (it indeed looks like we're working with the Django request instead of the DRF one).Wasn't able to repro this yet -- @Audiopolis What does the request look like in your app? I assume it's a POST? Does it contain any form data, uploaded files, etc.? Do you access anything on the request in the view?
Thanks for the additional context @sentrivana. I don't have the full body anymore, but I believe it was indeed a POST request containing a JSON payload. All the logic succeeded (including feeding the payload into a serializer that validated the data and used it to create an object) until it attempted to send an email through a third-party service, which failed, triggering an exception log. In other words, the DRF request has been read multiple times, and at some point, it seems to stop being a DRF request.
We are using this middleware:
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"nplusone.ext.django.NPlusOneMiddleware",
]
In this environment, we are also using debug_toolbar.middleware.DebugToolbarMiddleware
.
I have not had time yet to try to create a reproduction.
from sentry-python.
Related Issues (20)
- Create Ray Serve integration
- Stop Using `Hub` in `HttpTransport`
- Move `sentry_sdk.init` implementation out of `hub.py`
- Hardcoded transaction name for ARQ cron jobs HOT 2
- Improve POTel span/description/status logic
- Disable POTel autoinstrumentation
- Determine lowest compatible `opentelemetry-distro` (`-api`, `-sdk`) version
- BeforeSend() for Spans
- TypeError when instantiating Starlette middleware with positional arguments HOT 4
- Improve `record_lost_event` parameter documentation
- Load Balancer with 2-way SSL authentication support HOT 4
- UI Indication when data has been truncated > 10 limit HOT 1
- Error when using Annotated with django-stubs and mypy HOT 2
- Emit deprecation warnings for `Hub`-based APIs HOT 1
- KeyError('sentry-monitor-start-timestamp-s') HOT 6
- Missing `in_progress` checkin with Cron Monitoring HOT 9
- Deprecate `init` context manager
- Strawberry Integration - Tracing Does Not Appear to Work HOT 8
- Add support for FastAPI background tasks HOT 1
- 422 is not reported despite setting `failed_request_status_codes` HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sentry-python.