CLAUDE LABJP
2.1.273 — A round of connection work landed together: five opt-in headers for LLM gateways, and a notice when Claude Code stops trying to reconnect an MCP server09/29 — The date beside claude-sonnet-4-5 is 12 days out, but it is an earliest-possible estimate. The model is still Active, and public retirements get at least 60 days noticeMCP — People keep asking to reconnect a dropped server without ending the session. The disconnect is now announced, but reattaching is still something you do by handNEW — A scheduled task ran some days and not others. The cause was that only one folder had been bound to itWINDOWS — When Cowork fails on its very first task, check developer mode and the setup state before going looking for a causeHANDOFF — Before a long draft gets too heavy for one chat, decide on the three things the summary must carry into the next one2.1.273 — A round of connection work landed together: five opt-in headers for LLM gateways, and a notice when Claude Code stops trying to reconnect an MCP server09/29 — The date beside claude-sonnet-4-5 is 12 days out, but it is an earliest-possible estimate. The model is still Active, and public retirements get at least 60 days noticeMCP — People keep asking to reconnect a dropped server without ending the session. The disconnect is now announced, but reattaching is still something you do by handNEW — A scheduled task ran some days and not others. The cause was that only one folder had been bound to itWINDOWS — When Cowork fails on its very first task, check developer mode and the setup state before going looking for a causeHANDOFF — Before a long draft gets too heavy for one chat, decide on the three things the summary must carry into the next one
Articles/API & SDK
API & SDK/2026-09-17Advanced

I Send Images Twenty at a Time — The Day the 21st Image Changed the Rules for the Other 61

Sending 62 images in one request failed with invalid_request_error. The cause was the image count, not the payload size. Here is how I recounted visual tokens as 28px patches and built batches that respect count, dimensions, and payload at once.

Claude API122Vision4visual tokensbatchingindie development24

Premium Article

One morning I tried to hand an entire asset folder over for sorting. I packed all 62 images into a single request, and what came back was not a set of labels. It was invalid_request_error.

My first suspicion was payload size. But when I measured it, the base64 payload came to 15.19 MB — less than half of the 32 MB request ceiling. Not one image was anywhere near the 10 MB per-image limit either.

The request had failed on count, not on bytes.

The 21st Image Changes the Terms for the Other 61

There is a sentence in the "Request limits" section of the docs that is easy to skim past. When a single request contains more than 20 images, a stricter per-image dimension limit applies to every image in that request. Images that exceed it are rejected with an invalid_request_error whose message mentions "many-image requests."

So the 21st image is not simply refused on its own. It raises the bar for images one through twenty as well. There are only two ways around it: keep every image at 2000 px or under on both sides, or keep the request to 20 or fewer image and document blocks. The second is the sturdier of the two, because it doesn't constrain what your source material is allowed to look like.

What counts toward that threshold is broader than I assumed. Images you resend as conversation history count. Images nested inside tool_result — screenshots returned to computer use, for instance — count. On Amazon Bedrock and Google Cloud, document blocks such as PDFs count too. The longer an agent loop runs, the closer you drift to the threshold even on turns where you only added one picture yourself.

Of my 62 images, 8 had a long edge over 2000 px. Split into groups of twenty, all 8 go through untouched. Only when they rode in one combined request did those same 8 become the ones that took the whole thing down.

Visual Tokens Are Tiles, Not a Division of Area

Fixing the estimate meant fixing how I was counting in the first place.

I had been using "area divided by 750." That is fine for getting the order of magnitude right. It is far too coarse for deciding whether you are just under a limit. The actual rule cuts the image into 28×28 pixel tiles and counts them.

visual tokens = ceil(width / 28) × ceil(height / 28)

The two separate ceilings are the part that matters. Claude then pads every image — resized or not — out to the next multiple of 28 on the bottom and right edges. That padding holds no content, so when you work with coordinates you normalize against the resized dimensions, never the padded ones.

Downscaling is also governed by two conditions rather than one. Each model has an edge limit and a visual token limit, and Claude picks the largest aspect-preserving size that satisfies both.

TierModelsMax long edgeMax visual tokens
StandardAll other models1568 px1568
High-resolutionClaude 4.7 and later2576 px4784

For photos and screenshots, the token limit is usually what binds first. The edge limit only takes over on elongated images — panoramas, tall phone screenshots, that sort of shape.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
You will be able to count visual tokens from your own asset dimensions first, and correct your estimate before the day a newer model tier triples your image input
You will be able to avoid the boundary where adding a 21st image rejects the entire request with invalid_request_error, before a production batch hits it
You will be able to tell whether compression or resizing is what actually moves your bill, and stop spending time on the optimization that does neither
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $15 for lifetime access
View Membership →

Related Articles

API & SDK2026-07-13
Full-Size or Downscaled? A Per-Image Resolution Rule for Opus 4.7's High-Resolution Vision
Opus 4.7 finally read the fine texture in my wallpapers, so I sent everything at full size. My weekly image tokens jumped 2.4x. Here is the preflight that decides resolution and model per image, with the measured savings.
API & SDK2026-07-10
Don't Trust the Confidence Score: Per-Class Calibration and Abstain Routing for Vision Classification
Overall accuracy looked fine while individual categories quietly collapsed. Here is how I calibrated Claude Vision's self-reported confidence per class and routed abstentions to a human queue.
API & SDK2026-05-15
Automating Wallpaper Classification with Claude Vision API — Accuracy, Cost, and a Batch Job That Survives Interruptions
A firsthand account of automating wallpaper category classification with the Claude Vision API. Honest numbers on accuracy and cost, plus the batch design that stopped me re-paying for the same images.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links