When building RESTful APIs with Django, the default error pages 404 Not Found
(when you try to access an unavailable url), 500 Internal Server Error
, return HTML responses. While this is fine for traditional web apps, API clients expect JSON responses instead.
In this article, I’ll walk through how to override Django’s error handlers using handler404
and handler500
, and return consistent, structured JSON responses for your API.
Why Customize Error Handlers?
By default, Django shows pages like this when an error occurs:
- 404 → “Page not found” (HTML template)
- 500 → “Server error” (HTML template)
For API consumers, this is not helpful. Instead, something like this should be returned:
{
"status": "Failed",
"message": "he requested resource was not found"
}
or
{
"status": "Failed",
"message": "Internal Server Error"
}
Setting Up Custom Exception Handlers
First, create a file called custom_exceptions.py
inside your API service folder (for example api_services/custom_exceptions.py
).
# api_services/custom_exceptions.py
from django.http import JsonResponse
class CustomException:
@staticmethod
def custom_404_view(request, exception=None):
return JsonResponse(
{"status": "Failed", "message": "The requested resource was not found"},
status=404
)
@staticmethod
def custom_500_view(request):
return JsonResponse(
{"status": "Failed", "message": "Internal Server Error"},
status=500
)
-
custom_404_view
→ handles invalid routes. -
custom_500_view
→ handles unexpected server errors.
We’re using JsonResponse
here because it works outside of Django REST Framework (DRF) and guarantees valid JSON output.
Registering Handlers in urls.py
Now tell Django to use these handlers globally. In your project’s main urls.py
file:
from django.contrib import admin
from django.urls import path, include
from django.conf.urls import handler404, handler500
from api_services.custom_exceptions import CustomException
BASE_PREFIX = "api/v1"
urlpatterns = [
path("admin/", admin.site.urls),
path(f"{BASE_PREFIX}/users/", include("apis.users.urls")),
]
# Attach custom error handlers
handler404 = CustomException.custom_404_view
handler500 = CustomException.custom_500_view
Important: Turn Off Debug Mode
By default, Django shows detailed debug pages when DEBUG = True
.
This is useful for developers, but it overrides your custom error handlers.
To make your JSON handlers work, set this in settings.py
:
DEBUG = False
ALLOWED_HOSTS = ["*"] # Or set to your domain(s)
Now Django will call your custom_404_view
and custom_500_view
instead of showing HTML pages.
Testing the Setup
- Run your server
python manage.py runserver
- Try hitting an invalid endpoint:
GET http://127.0.0.1:8000/api/v1/use
You’ll now get a clean JSON response:
{
"status": "Failed",
"message": "The requested resource was not found"
}
- For
500
errors, you can temporarily raise an exception in a view and see the JSON response.
Why This Matters
- ✅ Cleaner API: Clients always get JSON, no ugly HTML errors.
- ✅ Consistency: Same error format as your success responses.
- ✅ Better UX: Frontend apps can handle errors gracefully.
Top comments (0)