Channels: Channels + rest framework: exception after file upload causes endless exception loop

Created on 27 Sep 2017  路  12Comments  路  Source: django/channels

I've encountered a very annoying bug that seems directly related to channels.AsgiRequest.

  • Channels + asgi_redis
  • Django debug turned on
  • Have a django/rest_framework handler accepting a file upload
  • raise from this handler
  • While attempting to return 500 response page, Django will raise exception again
  • Catches exception, and tries to return 500 again...

  • OS, runtime environment,browser: Ubuntu 16.04, Python 3.6, curl )
  • Library versions: channels-1.1.8, daphne-1.3.0, django-1.11.5, twisted-17.9.0, asgi_redis-1.4.3, rest_framework-3.6.4
  • Django debug turned on (important)
  • Expected behavior: show an exception message in log, return 500 to the client
  • Actual behavior: exception loops in the server, client hangs
  • How you're running Channels: runserver + redis. Same situation with daphne.
  • Console logs and full tracebacks of any errors:
    This exception repeats in the 'loop':
Traceback (most recent call last):
  File "/home/alexey.nazarenko/.pyenv/versions/p7reloaded_py/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/home/alexey.nazarenko/.pyenv/versions/p7reloaded_py/lib/python3.6/site-packages/django/utils/deprecation.py", line 140, in __call__
    response = self.get_response(request)
  File "/home/alexey.nazarenko/.pyenv/versions/p7reloaded_py/lib/python3.6/site-packages/django/core/handlers/exception.py", line 43, in inner
    response = response_for_exception(request, exc)
  File "/home/alexey.nazarenko/.pyenv/versions/p7reloaded_py/lib/python3.6/site-packages/django/core/handlers/exception.py", line 93, in response_for_exception
    response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  File "/home/alexey.nazarenko/.pyenv/versions/p7reloaded_py/lib/python3.6/site-packages/django/core/handlers/exception.py", line 139, in handle_uncaught_exception
    return debug.technical_500_response(request, *exc_info)
  File "/home/alexey.nazarenko/.pyenv/versions/p7reloaded_py/lib/python3.6/site-packages/django/views/debug.py", line 81, in technical_500_response
    text = reporter.get_traceback_text()
  File "/home/alexey.nazarenko/.pyenv/versions/p7reloaded_py/lib/python3.6/site-packages/django/views/debug.py", line 333, in get_traceback_text
    c = Context(self.get_traceback_data(), autoescape=False, use_l10n=False)
  File "/home/alexey.nazarenko/.pyenv/versions/p7reloaded_py/lib/python3.6/site-packages/django/views/debug.py", line 300, in get_traceback_data
    'filtered_POST_items': list(self.filter.get_post_parameters(self.request).items()),
  File "/home/alexey.nazarenko/.pyenv/versions/p7reloaded_py/lib/python3.6/site-packages/django/views/debug.py", line 167, in get_post_parameters
    return request.POST
  File "/home/alexey.nazarenko/.pyenv/versions/p7reloaded_py/lib/python3.6/site-packages/channels/handler.py", line 160, in _get_post
    self._load_post_and_files()
  File "/home/alexey.nazarenko/.pyenv/versions/p7reloaded_py/lib/python3.6/site-packages/django/http/request.py", line 299, in _load_post_and_files
    self._post, self._files = self.parse_file_upload(self.META, data)
  File "/home/alexey.nazarenko/.pyenv/versions/p7reloaded_py/lib/python3.6/site-packages/django/http/request.py", line 255, in parse_file_upload
    warning="You cannot alter upload handlers after the upload has been processed."
  File "/home/alexey.nazarenko/.pyenv/versions/p7reloaded_py/lib/python3.6/site-packages/django/http/request.py", line 248, in upload_handlers
    raise AttributeError("You cannot set the upload handlers after the upload has been processed.")
AttributeError: You cannot set the upload handlers after the upload has been processed.

bug exintermediate

Most helpful comment

I have same problem with DRF. Any suggestion?

All 12 comments

Simple (probably, not minimal) example app:

rest_upload_fail.zip

Offending request:

curl -F "inputs=@$HOME/tmp/test.txt" http://127.0.0.1:8000/users/1/oppana/

Yup, looks like something about the 500 handling is slightly off, which is weird, as the request handling code is basically copied from Django.

That's one quick response )

It looks like we're missing something like hasattr(self, '_files') check somewhere, but I can't be sure.

I have same problem with DRF. Any suggestion?

Same here with DRF. General http 500 exception gives me this.

I get the same error when using DRF

I found that this error occurs for me when serializer use UniqueTogether validator, so I replaced it on custom validate field e.g:
def validate(self, data):
post = data['post']
if SavedPost.objects.filter(user_id=self.context['request'].user.id, post_id=post).exists():
raise ValidationError("This post was already saved")
return data

maybe it will help someone.

Hi everyone. I believe this has been fixed by encode/django-rest-framework#5590.

If anyone has the time, it'd be appreciated if you could verify the fix by testing your code against the DRF master branch.

@rpkilby
Hello Ryan.
Yes, now issue is fixed. But I've tested only one case.

channels==1.1.8 + djangorestframework==3.7.3 (master)

Thank you!

Hello, are there any updates on this issue? I am using the same configuration as @mark-mishyn , but I still get the error

Hi @SHohentanner - have you tried installing the latest release (3.7.7)? It should no longer be necessary to install DRF from the master branch.

Closing as it's been fixed on the DRF end (thanks for that!)

Was this page helpful?
0 / 5 - 0 ratings