A Django HTTP 400 Bad Request error indicates that the web server rejected an incoming client HTTP request before processing view logic. In production (when DEBUG = False), Django triggers a 400 error for security violations—most commonly caused by unconfigured ALLOWED_HOSTS headers, CSRF token mismatches, or malformed JSON payloads.
Cause 1: Missing Domain in settings.py ALLOWED_HOSTS (Most Common)
When deploying Django to production with DEBUG = False, Django validates incoming Host: headers against ALLOWED_HOSTS. If the domain or IP is missing, Django responds with HTTP 400:
# Add your production domain name, subdomains, and server IP address
ALLOWED_HOSTS = [
'example.com',
'www.example.com',
'192.168.1.100',
'localhost',
'127.0.0.1'
]Cause 2: Malformed JSON Payloads in REST APIs
If a client sends an invalid JSON string (e.g. trailing commas or unquoted keys) to a Django REST Framework API, Django throws a 400 Bad Request during request parsing:
import json
from django.http import JsonResponse, HttpResponseBadRequest
def api_endpoint(request):
if request.method == 'POST':
try:
data = json.loads(request.body)
except json.JSONDecodeError:
return HttpResponseBadRequest(JsonResponse({'error': 'Invalid JSON body format'}))
return JsonResponse({'status': 'success'})
Comments and corrections