Fix uWSGI "invalid request block size"
Fix the uWSGI error invalid request block size behind Nginx for Django: use uwsgi_pass instead of proxy_pass for the uwsgi protocol, match socket and http-socket, and raise buffer-size for large cookies and headers.
Problem statement
Requests fail with 502 Bad Gateway or an empty response, and the uWSGI log shows:
invalid request block size: 21573 (max 4096)...skip
or the number is suspiciously large, like invalid request block size: 21536 (max 4096). uWSGI rejected the request before Django saw it. Either Nginx is speaking plain HTTP to a socket that expects uWSGI's binary protocol, or a real uwsgi-protocol request carries more headers and cookies than uWSGI's default 4 KB buffer allows.
- If Nginx uses
proxy_pass, uWSGI must listen withhttp-socket; if uWSGI usessocket, Nginx must useuwsgi_passwithinclude uwsgi_params. - Never point a browser or
curldirectly at a uwsgi-protocolsocket. - For large cookies or headers, raise
buffer-size = 32768in the uWSGI config. - Reduce cookie bloat from analytics or large session cookies where possible.
Step-by-step solution
1. Decide which protocol you use
uWSGI can listen in two different ways:
socket = /run/uwsgi/app.sock(or:3031): the binary uwsgi protocol. Nginx must talk to it withuwsgi_pass.http-socket = :8000: plain HTTP. Nginx talks to it withproxy_pass, and curl can test it.
The error with a block size in the tens of thousands is usually HTTP sent to a uwsgi socket: uWSGI reads the first bytes of GET / HTTP/1.1 as a packet header and gets a nonsense size (for GET, the bytes E and T read as a little-endian 16-bit length give exactly 21573; POST gives 21327).
2. Match Nginx to the socket type
For the uwsgi protocol:
location / {
include uwsgi_params;
uwsgi_pass unix:/run/uwsgi/myapp.sock;
uwsgi_param HTTP_X_FORWARDED_PROTO $scheme;
}
[uwsgi]
socket = /run/uwsgi/myapp.sock
chmod-socket = 660
For HTTP:
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
[uwsgi]
http-socket = 127.0.0.1:8000
Do not confuse http-socket with http, which starts uWSGI's own HTTP router as a separate process; behind Nginx you want http-socket or socket.
3. Raise the buffer for large headers
If the protocols match and the reported size is moderate (5,000 to 30,000 bytes), the request headers really are larger than 4 KB. Large cookies from analytics tools, many Set-Cookie values on one domain, or big JWTs in headers cause this:
[uwsgi]
buffer-size = 32768
The maximum is 65535. Larger values cost memory per worker, so do not set it higher than needed.
4. Shrink what the browser sends
Every cookie for your domain is sent on every request, including static files on the same host. Check the size:
curl -s -o /dev/null -w "%{size_request}\n" -H "Cookie: $(cat cookies.txt)" https://example.com/
Options: serve static files from a cookieless domain or CDN, keep sessions server-side (Django's default database or cache sessions store only an ID in the cookie), and avoid storing data in signed-cookie sessions.
5. Match related Nginx buffers
When headers are large on the way in, responses often carry large headers on the way out too. Keep Nginx's uwsgi_buffer_size (or proxy_buffer_size) in line, or you will hit "upstream sent too big header" next:
uwsgi_buffer_size 32k;
uwsgi_buffers 8 32k;
Verification check: reload both services and request a page with a large cookie set; the uWSGI log should show normal request lines and no invalid request block size. If uWSGI listens on a TCP port, make sure it is bound to 127.0.0.1 or a private address, never 0.0.0.0 on a public interface.
Explanation
The uwsgi protocol starts every request with a 4-byte header containing a 16-bit length for the packet that follows. When plain HTTP arrives instead, uWSGI interprets the ASCII bytes of the request line as that header and reads an absurd length. When real uwsgi packets arrive, the length is genuine, and uWSGI compares it with buffer-size, which is 4,096 bytes by default to keep per-request memory small. Either way, uWSGI drops the request without passing it to Django, so Django's logs show nothing.
Edge cases / notes
- Internet scanners hitting an exposed uwsgi port produce the same message with random sizes. Bind to localhost or a socket file.
- Load balancers sending health checks over HTTP to a
socket=port trigger it on every check; add anhttp-socketfor them or check through Nginx. - Docker. If Nginx and uWSGI are separate containers, confirm both configs after any image update.
- Gunicorn speaks only HTTP, so migrating to it removes this class of error.
Next steps
- Review the full setup in Deploy Django With uWSGI and Nginx.
- For large response headers, see Fix Nginx Upstream Sent Too Big Header.
FAQ
What is the difference between socket and http-socket in uWSGI?
socket speaks the binary uwsgi protocol for uwsgi_pass; http-socket speaks HTTP for proxy_pass and direct testing.
What buffer-size should I use?
Start with 8192 or 16384 if cookies are large. 32768 covers almost all real cases; 65535 is the maximum.
Can I test a uwsgi socket with curl?
No. Use uwsgi_curl or test through Nginx, or add an http-socket for testing.
Why does Django log nothing?
uWSGI rejects the request before it reaches the application.