Django3, custom 404 page redirects to 500 when Debug=False because Django cannot find exception parameter

When Debug = True django returns a Page not found (404) page which is totally fine

But when I change Debug = False django return a Server Error (500) and the server shows these requests made:

[30/Jul/2022 12:29:44] "GET /__reload__/events/ HTTP/1.1" 500 145
[30/Jul/2022 12:29:44] "GET /__reload__/events/ HTTP/1.1" 500 145
[30/Jul/2022 12:29:44] "GET /sdfs HTTP/1.1" 500 145
[30/Jul/2022 12:29:45] "GET /favicon.ico HTTP/1.1" 302 0

myproject main urls.py

from django.conf.urls import handler404
handler404 = 'myproject.views.custom_page_not_found'

please note here that hander404 is not found by django

my views.py

def custom_page_not_found(request, exception, template_name="errors/404.html"):
    return render(request, template_name, status=404)

Please not here django cannot find the exception parameter
Capture

In previous community questions i could not find any question that points to the exception parameter not found issue. Please note that i am not using django templates {% %} in my 404.html file

I think when django does not find the exception parameter it returns server error 500.

I think this is an issue with finding the template. Is errors a directory within your project base dir templates? (In other words project_dir/templates/errors/404.html)

Also, what is your TEMPLATES setting?

  • Yes exactly the path to templates is project_dir\templates\errors\404.html

  • Template settings is as follows

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]
    
  • When I return the views with HttpResponse & render method with request parameter set to None it works and 404.html page renders:

    return HttpResponse('<html><body>404</body></html>', status=404)
    return render(None, 'errors/404.html', status=404)

    But in this case 404.html doesnt display data coming from django templates tags.

  • I also have separate template folders inside each application where i store templates related to that particular app.

What versions of Python and Django are you using?

Also you could try changing your function signature to:

def custom_page_not_found(*args, **kwargs):

and then print(args) and print(kwargs) to see what you are getting passed.

Version Django==3.2.9

args = (<WSGIRequest: GET '/sdfasdf'>,)

kwargs = {'exception': Resolver404({'tried': [[<URLPattern '' [name='home_page']>], [<URLPattern 'cookie-policy' [name='cookie-policy']>], [<URLPattern 'about-us' [name='about-us']>], [<URLResolver <URLPattern list> (admin:admin) 'admin/'>], [<URLResolver <module 'blogs.urls' from 'C:\\Users\\Dell\\Desktop\\Django Projects\\healthslash\\blogs\\urls.py'> (None:None) 'blogs/'>], [<URLResolver <module 'tools.urls' from 'C:\\Users\\Dell\\Desktop\\Django Projects\\healthslash\\tools\\urls.py'> (None:None) 'tools/'>], [<URLResolver <module 'crm.urls' from 'C:\\Users\\Dell\\Desktop\\Django Projects\\healthslash\\crm\\urls.py'> (None:None) 'crm/'>], [<URLResolver <module 'debug_toolbar.toolbar' from 'C:\\Users\\Dell\\.virtualenvs\\healthslash-aqa9QL1m\\lib\\site-packages\\debug_toolbar\\toolbar.py'> (djdt:djdt) '__debug__/'>], [<URLResolver <module 'django_browser_reload.urls' from 'C:\\Users\\Dell\\.virtualenvs\\healthslash-aqa9QL1m\\lib\\site-packages\\django_browser_reload\\urls.py'> (django_browser_reload:django_browser_reload) '__reload__/'>], [<URLPattern 'robots.txt'>], [<URLPattern 'favicon.ico'>], [<URLPattern 'sitemap.xml'>]], 'path': 'sdfasdf'})}

So - what this is telling us is that exception is not a positional parameter - it’s a keyword parameter.

You could try:
def custom_page_not_found(request, exception=None, template_name="errors/404.html"):

or leave it at:
def custom_page_not_found(request, **kwargs):
and get the keyword args from kwargs as needed. (e.g. kwargs.get('template_name', 'errors/404.html')

or anything else along those lines.

def custom_page_not_found(request, exception=None, template_name="errors/404.html"):
    return render(request, template_name, status=404)

It’s working now even the data from the templates tags is coming through.

I am a beginner and it’s been a year since I started learning Django. Can you tell me what was going wrong? or reference an article/blog for that matter?

Actually I can’t - this surprised me as well. When I started looking at this, I more-or-less stumbled across this solution and I can’t say I know why it’s behaving like this.

What version of Python are you using?

Python version = python 3.10.1

I see that Django 3.2.9 added Python 3.10 compatibility - if you’re really curious about it, you could either try updating to the latest 3.2 branch or going back to a Python 3.9 instance just to see if there are some version-related issues involved.

(I don’t see anything in any of the newer Django 3.2.x release notes identifying a bug in that area. so that’s probably not the issue there - but I’d try updating anyway just to see.)