uWSGI File Wrapper and Python 3.5

uWSGI File Wrapper and Python 3.5

A couple of weeks ago we hit a small but hard to track issue in one of our clients. They opened an issue telling us that the downloaded files appeared as corrupt. After closer examination, the downloaded files had 0 bytes. The HTTP response was a solid 200 OK with a 0 bytes file attachment.

This was very strange, given that no automatic error reports had been triggered and there was clearly an error. Moreover we noticed that this issue in particular happened whenever the backend Django app returned a file in the response.

This is quite rare in a production environment, given that you most certainly don’t want the Django app handling files, but rather links to the files. However, one usual exception for this rule are small dynamic reports (for bigger ones you’ll want to send an email link when its ready).

On the Django logs we could clearly see that the reports were properly created and no errors were present neither there nor in the NGINX logs.

That left us to take a peek at the application server logs, in this case, uWSGI. It was there that we got to see the following:

					io.UnsupportedOperation: fileno

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
 File "/usr/local/lib/python3.5/site-packages/django/core/handlers/wsgi.py", line 199, in __call__
 response = environ['wsgi.file_wrapper'](response.file_to_stream)
SystemError: <built-in function uwsgi_sendfile> returned a result with an error set

After Googling around a bit we found a great explanation of the issue plus a fix at http://beenje.github.io/blog/posts/uwsgi-send_file-and-python35/.

We had updated from Python 3.4 to Python 3.5 in a previous deploy, but no errors had been detected so far because no reports were needed until the end of that month 🙂

See related posts

From Python to Go or Rust?

Motivation Nowadays there are plenty of options for building backend systems, both in terms of programming languages as well as frameworks, each of them having their own strengths and weaknesses. In Octobot we’ve been working with Python/Django.

Read more