sentry-python icon indicating copy to clipboard operation
sentry-python copied to clipboard

RawPostDataException being raised alongside other error

Open mikicz opened this issue 6 months ago • 1 comments

How do you use Sentry?

Self-hosted/on-premise

Version

2.29.1

Steps to Reproduce

Installed versions - this should be the relevant bits, we've got hundreds of packages

Django==5.2.3
djangorestframework==3.16.0
sentry-sdk==2.29.1

We've got a fairly standard serializer which on save inserts/updates some data in database. A user submitted the serializer in such a way which caused a integrity error in the database.

The error itself looks like this:

UniqueViolation: duplicate key value violates unique constraint "master_vendor_data_unusedsupplierreviewed_supplier_id_key"
DETAIL:  Key (supplier_id)=(15848) already exists.

  File "django/db/backends/utils.py", line 105, in _execute
    return self.cursor.execute(sql, params)

IntegrityError: duplicate key value violates unique constraint "master_vendor_data_unusedsupplierreviewed_supplier_id_key"
DETAIL:  Key (supplier_id)=(15848) already exists.

  File "django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "django/views/decorators/csrf.py", line 65, in _view_wrapper
    return view_func(request, *args, **kwargs)
  File "django/views/generic/base.py", line 104, in view
    return self.dispatch(request, *args, **kwargs)
  File "rest_framework/views.py", line 515, in dispatch
    response = self.handle_exception(exc)
  File "rest_framework/views.py", line 475, in handle_exception
    self.raise_uncaught_exception(exc)
  File "rest_framework/views.py", line 486, in raise_uncaught_exception
    raise exc
  File "rest_framework/views.py", line 512, in dispatch
    response = handler(request, *args, **kwargs)
  File "rest_framework/generics.py", line 194, in post
    return self.create(request, *args, **kwargs)
  File "src/common/views/abstract_child_view.py", line 17, in wrapper
    return func(request, *args, **kwargs)
  File "src/tenant/master_vendor_data/views/base_reviewed_view.py", line 86, in create
    self.perform_create(serializer)
  File "src/tenant/master_vendor_data/views/base_reviewed_view.py", line 74, in perform_create
    return self._save_and_add_system_comment(serializer)
  File "src/tenant/master_vendor_data/views/base_reviewed_view.py", line 54, in _save_and_add_system_comment
    instance: BaseReviewedModel = serializer.save(
  File "rest_framework/serializers.py", line 210, in save
    self.instance = self.create(validated_data)
  File "rest_framework/serializers.py", line 991, in create
    instance = ModelClass._default_manager.create(**validated_data)
  File "django/db/models/manager.py", line 87, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "django/db/models/query.py", line 663, in create
    obj.save(force_insert=True, using=self.db)
  File "django/db/models/base.py", line 902, in save
    self.save_base(
  File "django/db/models/base.py", line 1008, in save_base
    updated = self._save_table(
  File "django/db/models/base.py", line 1169, in _save_table
    results = self._do_insert(
  File "django/db/models/base.py", line 1210, in _do_insert
    return manager._insert(
  File "django/db/models/manager.py", line 87, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "django/db/models/query.py", line 1864, in _insert
    return query.get_compiler(using=using).execute_sql(returning_fields)
  File "django/db/models/sql/compiler.py", line 1882, in execute_sql
    cursor.execute(sql, params)
  File "django/db/backends/utils.py", line 79, in execute
    return self._execute_with_wrappers(
  File "django/db/backends/utils.py", line 92, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "django/db/backends/utils.py", line 100, in _execute
    with self.db.wrap_database_errors:
  File "django/db/utils.py", line 91, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "django/db/backends/utils.py", line 105, in _execute
    return self.cursor.execute(sql, params)

Expected Result

Only one exception gets captured

Actual Result

Many exceptions get raised alongside the main exception. 20 got created in Sentry.

Image

The RawPostDataException traceback looks like this:

UniqueViolation: duplicate key value violates unique constraint "master_vendor_data_unusedsupplierreviewed_supplier_id_key"
DETAIL:  Key (supplier_id)=(15848) already exists.

  File "django/db/backends/utils.py", line 105, in _execute
    return self.cursor.execute(sql, params)

IntegrityError: duplicate key value violates unique constraint "master_vendor_data_unusedsupplierreviewed_supplier_id_key"
DETAIL:  Key (supplier_id)=(15848) already exists.

  File "django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "django/views/decorators/csrf.py", line 65, in _view_wrapper
    return view_func(request, *args, **kwargs)
  File "django/views/generic/base.py", line 104, in view
    return self.dispatch(request, *args, **kwargs)
  File "rest_framework/views.py", line 515, in dispatch
    response = self.handle_exception(exc)
  File "rest_framework/views.py", line 475, in handle_exception
    self.raise_uncaught_exception(exc)
  File "rest_framework/views.py", line 486, in raise_uncaught_exception
    raise exc
  File "rest_framework/views.py", line 512, in dispatch
    response = handler(request, *args, **kwargs)
  File "rest_framework/generics.py", line 194, in post
    return self.create(request, *args, **kwargs)
  File "src/common/views/abstract_child_view.py", line 17, in wrapper
    return func(request, *args, **kwargs)
  File "src/tenant/master_vendor_data/views/base_reviewed_view.py", line 86, in create
    self.perform_create(serializer)
  File "src/tenant/master_vendor_data/views/base_reviewed_view.py", line 74, in perform_create
    return self._save_and_add_system_comment(serializer)
  File "src/tenant/master_vendor_data/views/base_reviewed_view.py", line 54, in _save_and_add_system_comment
    instance: BaseReviewedModel = serializer.save(
  File "rest_framework/serializers.py", line 210, in save
    self.instance = self.create(validated_data)
  File "rest_framework/serializers.py", line 991, in create
    instance = ModelClass._default_manager.create(**validated_data)
  File "django/db/models/manager.py", line 87, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "django/db/models/query.py", line 663, in create
    obj.save(force_insert=True, using=self.db)
  File "django/db/models/base.py", line 902, in save
    self.save_base(
  File "django/db/models/base.py", line 1008, in save_base
    updated = self._save_table(
  File "django/db/models/base.py", line 1169, in _save_table
    results = self._do_insert(
  File "django/db/models/base.py", line 1210, in _do_insert
    return manager._insert(
  File "django/db/models/manager.py", line 87, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "django/db/models/query.py", line 1864, in _insert
    return query.get_compiler(using=using).execute_sql(returning_fields)
  File "django/db/models/sql/compiler.py", line 1882, in execute_sql
    cursor.execute(sql, params)
  File "django/db/backends/utils.py", line 79, in execute
    return self._execute_with_wrappers(
  File "django/db/backends/utils.py", line 92, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "django/db/backends/utils.py", line 100, in _execute
    with self.db.wrap_database_errors:
  File "django/db/utils.py", line 91, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "django/db/backends/utils.py", line 105, in _execute
    return self.cursor.execute(sql, params)

RawPostDataException: You cannot access body after reading from request's data stream
  File "django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "axes/middleware.py", line 47, in __call__
    response = self.get_response(request)
  File "django/core/handlers/exception.py", line 57, in inner
    response = response_for_exception(request, exc)
  File "django/core/handlers/exception.py", line 140, in response_for_exception
    response = handle_uncaught_exception(
  File "django/core/handlers/exception.py", line 185, in handle_uncaught_exception
    return callback(request)
  File "django/views/decorators/csrf.py", line 65, in _view_wrapper
    return view_func(request, *args, **kwargs)
  File "django/views/generic/base.py", line 104, in view
    return self.dispatch(request, *args, **kwargs)
  File "rest_framework/views.py", line 515, in dispatch
    response = self.handle_exception(exc)
  File "rest_framework/views.py", line 475, in handle_exception
    self.raise_uncaught_exception(exc)
  File "rest_framework/views.py", line 486, in raise_uncaught_exception
    raise exc
  File "rest_framework/views.py", line 503, in dispatch
    self.initial(request, *args, **kwargs)
  File "rest_framework/views.py", line 420, in initial
    self.perform_authentication(request)
  File "rest_framework/views.py", line 330, in perform_authentication
    request.user
  File "rest_framework/request.py", line 232, in user
    self._authenticate()
  File "rest_framework/request.py", line 385, in _authenticate
    user_auth_tuple = authenticator.authenticate(self)
  File "src/public/core/authentication.py", line 33, in authenticate
    response = super().authenticate(request)
  File "rest_framework/authentication.py", line 130, in authenticate
    self.enforce_csrf(request)
  File "rest_framework/authentication.py", line 145, in enforce_csrf
    reason = check.process_view(request, None, (), {})
  File "django/middleware/csrf.py", line 465, in process_view
    self._check_token(request)
  File "django/middleware/csrf.py", line 368, in _check_token
    request_csrf_token = request.POST.get("csrfmiddlewaretoken", "")
  File "rest_framework/request.py", line 431, in POST
    self._load_data_and_files()
  File "rest_framework/request.py", line 284, in _load_data_and_files
    self._data, self._files = self._parse()
  File "rest_framework/request.py", line 334, in _parse
    stream = self.stream
  File "rest_framework/request.py", line 207, in stream
    self._load_stream()
  File "rest_framework/request.py", line 314, in _load_stream
    self._stream = io.BytesIO(self.body)
  File "rest_framework/request.py", line 422, in __getattr__
    return getattr(_request, attr)
  File "django/http/request.py", line 363, in body
    raise RawPostDataException(

mikicz avatar Jun 17 '25 16:06 mikicz

@mikicz this could be a problem in djangorestframework or in sentry, so we'll need to reproduce first because it's a double body reading issue.

I see a self.stream in the second backtrace, could you give me your view code that uses streaming or a simple reproduction that helps me repro?

sl0thentr0py avatar Jun 18 '25 12:06 sl0thentr0py

Hi @mikicz, as @sl0thentr0py mentioned in his previous comment, we will need to be able to reproduce this problem in order to help here.

Are you still working on getting a reproduction you can share with us?

szokeasaurusrex avatar Jun 27 '25 12:06 szokeasaurusrex

I would like to take a look at some point, but so far haven't found the time for it just yet

mikicz avatar Jun 27 '25 18:06 mikicz

Hey @mikicz – I am going to close this issue for now, since we are still missing the information we would need in order to be able to reproduce this.

Once you have a reproduction, please feel free to reopen this issue or to open a new issue referencing this one 🙏

szokeasaurusrex avatar Jul 21 '25 09:07 szokeasaurusrex