solvedfeed

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_size on 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.

Continue reading — $1/month

The full fix, verbatim, plus every other solution in the feed.

raw markdown twin · ← back to feed