Fix RequestDataTooBig and TooManyFieldsSent in Django

Fix Django RequestDataTooBig, TooManyFieldsSent, and TooManyFilesSent errors: what each upload limit measures, raising limits safely per endpoint, and proxy limits.

Problem statement

A form submission, JSON API call, or admin bulk edit fails with a 400 Bad Request, and the logs show one of:

django.core.exceptions.RequestDataTooBig: Request body exceeded settings.DATA_UPLOAD_MAX_MEMORY_SIZE.
django.core.exceptions.TooManyFieldsSent: The number of GET/POST parameters exceeded settings.DATA_UPLOAD_MAX_NUMBER_FIELDS.
django.core.exceptions.TooManyFilesSent: The number of files exceeded settings.DATA_UPLOAD_MAX_NUMBER_FILES.

These are deliberate protections. Without them, a single request with a huge body or hundreds of thousands of form fields could consume a worker's memory and CPU. Django raises them as SuspiciousOperation subclasses, which produce a 400 response and are logged under django.security.RequestDataTooBig or similar logger names.

They are different from:

  • Nginx 413 Request Entity Too Large: the proxy rejected the body before Django saw it
  • Upload size validation in your form: application rules you wrote
  • FILE_UPLOAD_MAX_MEMORY_SIZE: a threshold for streaming uploads to disk, not a limit that rejects requests
Limits on a large requestClientlarge payloadNginxclient_max_body_sizeDjango parsingDATA_UPLOAD limitsViewor 400 responseLimits protect workers from a single oversized request; raise them deliberately.

Quick answer

  1. Identify which limit fired from the exception name.
  2. RequestDataTooBig: the non-file part of the request body exceeded DATA_UPLOAD_MAX_MEMORY_SIZE (2.5 MB by default). File uploads in multipart/form-data do not count toward it; large JSON bodies and big form fields do.
  3. TooManyFieldsSent: more than DATA_UPLOAD_MAX_NUMBER_FIELDS (1000 by default) parameters, common in large admin changelist edits and formsets.
  4. TooManyFilesSent: more than DATA_UPLOAD_MAX_NUMBER_FILES (100 by default) files in one request.
  5. Prefer fixing the request shape (pagination, batching, direct-to-storage uploads) over raising global limits.
  6. If you raise a limit, raise it moderately and consider per-view handling instead of global changes.
  7. Keep proxy limits (client_max_body_size) consistent with Django's limits.

Step-by-step solution

1. Find the exception and the endpoint

sudo journalctl -u gunicorn --since "1 hour ago" | grep -E "RequestDataTooBig|TooManyFieldsSent|TooManyFilesSent" -B2 | head -20

These exceptions are logged as security warnings. If your LOGGING configuration silences django.security, you may only see 400 responses in access logs. Add a handler for django.security at WARNING or above so they are visible.

2. Understand what each setting measures

SettingDefaultWhat it counts
DATA_UPLOAD_MAX_MEMORY_SIZE2621440 (2.5 MB)request body size excluding file upload data; checked when accessing request.body or request.POST
DATA_UPLOAD_MAX_NUMBER_FIELDS1000number of GET and POST parameters
DATA_UPLOAD_MAX_NUMBER_FILES100number of files in a multipart/form-data request
FILE_UPLOAD_MAX_MEMORY_SIZE2621440 (2.5 MB)uploads larger than this are streamed to a temporary file instead of kept in memory
four settings, four different limitsMeasures (default)DATA_UPLOAD_MAX_MEMORY_SIZE!body minus files (2.5 MB)DATA_UPLOAD_MAX_NUMBER_FIELDSGET and POST parameters (1000)DATA_UPLOAD_MAX_NUMBER_FILESfiles in one request (100)FILE_UPLOAD_MAX_MEMORY_SIZE✓memory vs temp file, not a limitFile uploads do not count toward the first limitdjango-deployment.com
A large JSON body counts in full, because it is not a file upload.

The DATA_UPLOAD_* settings can be set to None to disable the check, which removes the protection entirely and is not recommended for public endpoints.

3. RequestDataTooBig with JSON APIs

A JSON body counts fully toward DATA_UPLOAD_MAX_MEMORY_SIZE because it is read into memory as request.body. A client sending a 5 MB JSON array fails with the default settings.

large JSON: raise the limit or redesign?Raise the global limit✕every endpoint accepts big bodies✕memory per request growsquick, but broadTargeted✓raise it only for one view✓batch or paginate the payload✓upload a file, process in a taskThe limit exists to stop memory exhaustion from one requestdjango-deployment.com
Reading request.body after a custom check lets one view accept more.

Better options than raising the limit globally:

  • Batch the data: send records in chunks of a few hundred.
  • Upload a file instead: accept a multipart/form-data upload of a JSON or CSV file, which Django streams to disk, and process it in a background task.
  • Upload directly to object storage: issue a presigned URL, let the client upload, and send only the object key to Django.

If a specific integration genuinely needs a larger body, raise the limit to a reasoned value:

DATA_UPLOAD_MAX_MEMORY_SIZE = 10 * 1024 * 1024  # 10 MB

This applies to every request. Worker memory use for concurrent large requests grows accordingly.

4. RequestDataTooBig with forms that include files

For multipart/form-data, file contents are not counted, but every non-file field is. Forms that embed base64-encoded images in hidden fields, large rich-text content, or serialized state in a hidden input can exceed the limit. Send binary data as real file fields instead of base64 strings; base64 is about a third larger and counts toward the limit.

5. TooManyFieldsSent in the admin

Admin changelists with list_editable and large pages, or inline formsets with many rows, submit several fields per row. For example, 200 rows with 6 editable fields each, plus management form fields, exceeds 1000.

when the admin sends too many fieldsTooManyFieldsSent: The number ofGET/POST parametersexceededsettings.DATA_UPLOAD_MAX_NUMBER_FIELDS.DATA_UPLOAD_MAX_NUMBER_FIELDS =5000# admin-heavy site121Inlines and bulk actions send many fields.2Raise moderately; None disables the check.Smaller inline pages are often a better fix than a bigger limitdjango-deployment.com
list_per_page and fewer inline extras reduce the field count.

Fix the request shape first:

class ProductAdmin(admin.ModelAdmin):
    list_editable = ["price", "stock"]
    list_per_page = 50

For inlines, limit rows with max_num and extra, or edit large collections in a dedicated view with pagination.

If the form legitimately needs more fields (for example a bulk import confirmation screen used by staff), raise the limit moderately:

DATA_UPLOAD_MAX_NUMBER_FIELDS = 5000

The limit also covers query string parameters on GET requests, so extremely long filter URLs can trigger it too.

6. TooManyFilesSent

Multi-file upload widgets that submit hundreds of files in one request hit DATA_UPLOAD_MAX_NUMBER_FILES. Upload files in smaller batches from the client, or use direct-to-storage uploads that send one file per request. Raise the limit only if batches of that size are an intended feature.

7. Handling the error per view

Because the check happens when request.POST, request.FILES, or request.body is accessed, a view can catch it and return a clear message instead of a generic 400:

from django.core.exceptions import RequestDataTooBig
from django.http import JsonResponse


def import_records(request):
    try:
        payload = request.body
    except RequestDataTooBig:
        return JsonResponse(
            {"detail": "Payload too large. Send at most 1000 records per request."},
            status=413,
        )
    # ... parse and process payload ...

Middleware that reads request.POST or request.body before your view (for example logging or CSRF processing on POST requests) can trigger the exception earlier. CsrfViewMiddleware reads request.POST for form submissions, so for form posts the exception typically occurs before the view runs. Catching it in the view is most reliable for JSON APIs exempt from form-based CSRF.

8. Keep proxy limits consistent

Nginx rejects bodies larger than client_max_body_size (1 MB by default) with 413 before Django sees them:

server {
    client_max_body_size 25m;
}
keep every layer’s limit consistentNginx client_max_body_size413 before DjangoDjango DATA_UPLOAD_* settings400 with RequestDataTooBigForm or serializer validationfriendly messageAn outer limit below the inner one gives confusing 413sdjango-deployment.com
Set the proxy limit slightly above the largest request the app accepts.

Set it per location if only upload endpoints need large bodies:

location /api/imports/ {
    client_max_body_size 50m;
    proxy_pass http://unix:/run/myapp/gunicorn.sock;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
}

A CDN or load balancer in front may impose its own maximum as well. For large file uploads, Django's DATA_UPLOAD_MAX_MEMORY_SIZE usually does not need to change, because file content does not count toward it; the proxy limit is the one to raise.

9. Verify

Generate a request just above and just below the limits in staging:

python3 -c "import json; print(json.dumps([{'id': i, 'name': 'x' * 100} for i in range(20000)]))" > /tmp/big.json
ls -lh /tmp/big.json
curl -s -o /dev/null -w "%{http_code}\n" -X POST -H "Content-Type: application/json" \
  --data-binary @/tmp/big.json https://staging.example.com/api/imports/

Verification check:

  • requests within your intended limits succeed
  • oversized requests return a clear 400 or 413 response, not a 500
  • django.security warnings are logged and visible
  • Nginx limits are equal to or larger than the largest body you intend Django to accept

Explanation

Django parses request bodies lazily and enforces size and count limits during parsing, so a malicious or buggy client cannot force a worker to hold arbitrarily large data in memory or iterate over enormous numbers of fields. The defaults suit typical web forms. When legitimate traffic hits them, the usual cause is a request design that sends too much at once, and changing that design is safer than turning protections off.

Edge cases / notes

Large GET query strings

Very long URLs can also be rejected by Nginx (414 Request-URI Too Large) or by browsers before Django's field count applies.

Streaming request bodies

Django reads request bodies through the WSGI input stream. For very large uploads, streaming directly to object storage from the client is more efficient than any server-side setting.

DRF parsers

Django REST Framework's parsers read request.body or the stream through Django, so the same limits apply to API requests.

Designing large imports without raising limits

When a feature needs to accept large amounts of data, a staged design keeps web requests small and workers safe:

  1. Upload: the browser uploads a CSV or JSON file directly to object storage using a presigned URL, or to Django as a normal file field (file content does not count toward DATA_UPLOAD_MAX_MEMORY_SIZE).
  2. Register: the client sends a small request with the object key; Django creates an ImportJob row with status queued.
  3. Process: a Celery task streams the file, validates rows in batches, and writes results with bulk_create in chunks.
  4. Report: the job stores counts and errors; the UI polls a status endpoint or receives an email.
import csv
import io

from django.core.files.storage import default_storage


def iter_csv_rows(storage_key, batch_size=1000):
    with default_storage.open(storage_key, "rb") as raw:
        text = io.TextIOWrapper(raw, encoding="utf-8", newline="")
        batch = []
        for row in csv.DictReader(text):
            batch.append(row)
            if len(batch) >= batch_size:
                yield batch
                batch = []
        if batch:
            yield batch

Each batch is validated and saved independently, so memory use stays flat regardless of file size, and a single bad row does not have to fail the whole import.

Logging security exceptions visibly

These exceptions are reported through loggers under django.security. Make sure they reach your logs without flooding error trackers:

LOGGING["loggers"]["django.security"] = {
    "handlers": ["console"],
    "level": "WARNING",
    "propagate": False,
}

A sudden increase in RequestDataTooBig warnings can mean a client release started sending larger payloads, or that someone is probing your endpoints with oversized requests.

Common mistakes

  • Setting DATA_UPLOAD_MAX_MEMORY_SIZE = None globally to "fix" one import endpoint.
  • Confusing FILE_UPLOAD_MAX_MEMORY_SIZE with a maximum upload size.
  • Sending images as base64 strings in form fields.
  • Raising Django limits while Nginx still rejects the request with 413.

Next steps

FAQ

What is the default DATA_UPLOAD_MAX_MEMORY_SIZE in Django?

2.5 MB (2621440 bytes). It limits the request body size excluding file upload data, and is checked when Django reads request.body or parses request.POST.

Does DATA_UPLOAD_MAX_MEMORY_SIZE limit file uploads?

No. File contents in multipart/form-data requests are not counted. It limits JSON bodies, form fields, and other non-file data.

How do I fix TooManyFieldsSent in the Django admin?

Reduce the number of fields per request by lowering list_per_page for editable changelists or limiting inline rows. Raise DATA_UPLOAD_MAX_NUMBER_FIELDS moderately only if the form needs it.

Why does Django return 400 instead of 413 for large requests?

These exceptions are SuspiciousOperation subclasses, which Django turns into 400 Bad Request. You can catch them in a view and return 413 with a clearer message.

Keep going