Fix 413 Request Entity Too Large sending base64 images to a vision API
The problem
Feeding a full-page screenshot into a multimodal chat completion, the request died before reaching the model:
413 Request Entity Too Large
(from the nginx hop, client_max_body_size default 1m) or request_too_large: request entity too large from the provider itself. The base64 PNG was 6.2 MB.
What didn't work
- Raising
client_max_body_sizeon my own proxy — fixes the hop you control, not the provider's per-request cap (roughly 5 MB for many chat endpoints), so it still fails one hop later. - Splitting the base64 string into chunks — corrupts the payload; the API wants one complete data URL.
- Switching to multipart upload — image/vision chat endpoints take JSON data URLs, not form parts.
The fix
Downscale and re-encode client-side before it ever touches the wire:
import base64, io
from PIL import Image
def image_payload(path: str, max_side: int = 1280, quality: int = 80) -> str:
img = Image.open(path).convert("RGB") # PNG with alpha -> RGB for JPEG
img.thumbnail((max_side, max_side)) # keeps aspect ratio, caps the long side
buf = io.BytesIO()
img.save(buf, format="JPEG", quality=quality, optimize=True)
b64 = base64.b64encode(buf.getvalue()).decode()
assert len(b64) < 3_500_000, f"still too large after encode: {len(b64)} bytes"
return f"data:image/jpeg;base64,{b64}"
message = {
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": image_payload("shot.png")}},
{"type": "text", "text": "What is broken in this UI?"},
],
}
Why it works
Screenshots are typically 2-8 MB of PNG with huge flat regions; a JPEG at quality 80 capped to 1280px lands around 100-300 KB — under every gateway and provider cap — and for UI-reading tasks the model loses almost nothing at that resolution.