3

My custom middleware class seems to be skipping the process_exception stage during the response cycle

from django.utils.deprecation import MiddlewareMixin

class MyMiddleware(MiddlewareMixin):
    def process_request(self, request):
        print("Request!")

    def process_response(self, request, response):
        print("Response!")
        return response

    def process_exception(self, request, exception):
        print("Exception!")

Middleware configured....

DJANGO_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',
    'debug_toolbar.middleware.DebugToolbarMiddleware',
]

LOCAL_MIDDLEWARE = [
    'path.to.MyMiddleware',
]

MIDDLEWARE = DJANGO_MIDDLEWARE + LOCAL_MIDDLEWARE

and buried in my view code:

def some_view(request):
    ...
    raise Exception("foo")

However when I hit the url I get this in the console log:

Request!
Internal Server Error: /my/url/
Traceback (most recent call last):
  ... long traceback ...
  File "/path/to/my/views.py", line 184, in some_view
    raise Exception("foo")
Exception: foo
ERROR django.request 2019-01-24 11:50:48,270 [exception.py handle_uncaught_exception 118] Internal Server Error: /my/url/
Traceback (most recent call last):
  ... long traceback ...
  File "/path/to/my/views.py", line 184, in some_view
    raise Exception("foo")
Exception: foo
Response!

As you can see, process_exception isn't called at all, process_request and process_response both. And for some reason the exception traceback is shown twice before my middleware's process_response is even hit. The response that is passed to process_response for my middleware is a standard Django 500 debug page suggesting that the exception has been handled already, but I was under the impression that having my middleware as the last in the list meant it should be the first to be accessed for the response cycle?

EDIT So on further playing, looks like this is somehow related to DjangoDebugToolbar, when I disable that and remove the middleware my middleware works fine. I'm puzzled by that because my middleware should be firing first.

EDIT 2 Specifically it appears to be the profiling panel? commenting it out fixes the issue... how bizzare

ptr
  • 3,292
  • 2
  • 24
  • 48
  • Your code looks right to me. Are you sure "Exception!" isn't anywhere in the output? (You've elided it, so it's hard to be sure.) As a further test, try returning a response from your `process_exception()`. – Kevin Christopher Henry Jan 24 '19 at 13:44
  • I've checked the output- there's no trace of the print statement. I've added a pdb breakpoint in and it wasn't hit either, so the method is being skipped entirely. I'll keep digging to see if there's some archaic error handling further up in the code thats messing everything up – ptr Jan 24 '19 at 15:11
  • Updated the question- looks like debug toolbar is the cause. no solution yet – ptr Jan 24 '19 at 15:17

1 Answers1

1

So I eventually found https://github.com/jazzband/django-debug-toolbar/issues/497 which lists this as a bug with the Profiling panel in Django debug toolbar. Quite frustrating as it breaks in an extremely non-obvious way.

The fixes are either: Don't use profiling panel or put Django debug toolbar last in the list of middleware and accept that DDT won't monitor any of your middleware classes

ptr
  • 3,292
  • 2
  • 24
  • 48