We have a long standing Django web application that these days runs under Python 3 and a more modern version of Django . For as long as it has existed, it's had some forms that were rendered to HTML through templates, and it has rendered errors in those forms in what I think of as the standard way:
{{ form.non_field_errors }}
{% for field in form %}
[...]
{{ field.errors }}
[...]
{% endfor %}
This web application runs in Apache using mod_wsgi, and I've recently been working on moving the host this web application runs on to Ubuntu 24.04 (still using mod_wsgi). When I stood up a test virtual machine and looked at some of these HTML forms, what I saw was that when there were no errors, each place that errors would be reported was '[]' instead of blank. This did not happen if I ran the web application on the same test machine in Django's 'runserver' development testing mode.
At first I thought that this was something to do with locales, but the underlying cause is much more bizarre and inexplicable to me. The template operation for
form.non_field_errors
results in calling Form.non_field_errors(), which returns a django.forms.utils.ErrorList object (which is also what
field.errors
winds up being). This class is a multiple-inheritance subclass of UserList, list, and django.form.utils.RenderableErrorMixin . The latter is itself a subclass of django.forms.utils.RenderableMixin , which defines a __str__() special method value that is RenderableMixin.render(), which renders the error list properly, including rendering it as a blank if the error list is empty.
In every environment except under Ubuntu 24.04's mod_wsgi,
ErrorList.__str__
is
RenderableMixin.render
and everything works right for things like '
form.non_field_errors
' and '
field.errors
'. When running under Ubuntu 24.04's mod_wsgi, and only then,
ErrorList.__str__
is actually the standard
list.__str__
, so empty lists render as '[]' (and had I tried to render any forms with actual error reports, worse probably would have happened, especially since list.__str__ isn't carefully escaping special HTML characters).
I have no idea why this is happening in the 24.04 mod_wsgi. As far as I can tell, the method resolution order (MRO) for ErrorList is the same under mod_wsgi as outside it, and
sys.path
is the same. The RenderableErrorMixin class is getting included as a parent of ErrorList, which I can tell because RenderableMixin also provides a
__html__
definition, and
ErrorList.__html__
exists and is correct.
The workaround for this specific situation is to explicitly render errors to some format instead of counting on the defaults; I picked .as_ul(), because this is what we've normally gotten so far. However the whole thing makes me nervous since I don't understand what's special about the Ubuntu 24.04 mod_wsgi and who knows if other parts of Django are affected by this.
(The current Django and mod_wsgi setup is running from a venv, so it should also be fully isolated from any Ubuntu 24.04 system Python packages.)
(This elaborates on a grumpy Fediverse post of mine .)