Hmbown/CodeWhale · error
images exceed the attachment limit
Error message
images exceed the {MAX_RUNTIME_IMAGES} attachment limit What it means
The runtime image attach path enforces MAX_RUNTIME_IMAGES images per call; prepare_runtime_images bails before decoding when more are supplied. This is a hard count limit on inline images admitted into a single request's content blocks.
Solutions
- Split the request: send images across multiple turns/requests, keeping each batch within MAX_RUNTIME_IMAGES.
- Pre-select the most relevant images and drop the rest before calling the API.
- Raise MAX_RUNTIME_IMAGES only deliberately, since the limit protects the model context and payload size.
- In UI code, disable further attachments once the limit is reached and show a counter.
Example fix
// before
blocks = prepare_runtime_images(&all_30_images)?;
// after
for batch in all_30_images.chunks(MAX_RUNTIME_IMAGES) {
blocks.extend(prepare_runtime_images(batch)?);
} Defensive patterns
Strategy: validation
Validate before calling
if images.len() > MAX_RUNTIME_IMAGES {
return Err(anyhow!("too many images: {} > {}", images.len(), MAX_RUNTIME_IMAGES));
} Try / catch
match prepare_runtime_images(&images) {
Err(e) if e.to_string().contains("attachment limit") => {
eprintln!("send at most {} images per request", MAX_RUNTIME_IMAGES); }
other => other?,
} Prevention
- Cap the attachment queue in the UI at MAX_RUNTIME_IMAGES
- Batch images across turns instead of one request
- Summarize excess images in text rather than attaching all
When it happens
Trigger: Calling prepare_runtime_images with a slice of RuntimeImageInput whose length exceeds MAX_RUNTIME_IMAGES (e.g. pasting dozens of screenshots into one turn, or batching all images from a directory into one call).
Common situations: A user drags a whole screenshot folder into a session; an automation attaches every chart from a report; a loop that accumulates images without a cap.
Understand the failure class
Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.
Related errors
- images exceed the 5 MiB total limit
- evidence metadata exceeds limit
- image exceeds the MiB limit
- image has invalid base64
- image MIME does not match its content
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/0bfcbdbd14d709b6.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/image_attach.rs:106
if u64::from(width) * u64::from(height) > MAX_IMAGE_PIXELS
|| width > MAX_IMAGE_DIMENSION
|| height > MAX_IMAGE_DIMENSION
{
bail!("image dimensions exceed the decompression bomb guard; downscale or crop first");
}
let mut reader = ImageReader::new(Cursor::new(bytes)).with_guessed_format()?;
reader.limits(limits());
let decoded = reader
.decode()
.map_err(|_| anyhow::anyhow!("invalid image content or decode allocation limit"))?;
Ok((decoded, width, height))
}
/// Validate untrusted inline input before route selection or durable admission.
/// Return the existing provider-neutral history representation; no file is opened.
pub(crate) fn prepare_runtime_images(images: &[RuntimeImageInput]) -> Result<Vec<ContentBlock>> {
if images.len() > MAX_RUNTIME_IMAGES {
bail!("images exceed the {MAX_RUNTIME_IMAGES} attachment limit");
}
prepare_images_with_limit(
images,
MAX_RUNTIME_IMAGE_BYTES,
Some(MAX_RUNTIME_IMAGE_TOTAL_BYTES),
)
}
/// Internal Engine/history input retains the established local 5 MiB ceiling.
/// Network callers must first pass `prepare_runtime_images` (4 MiB per image,
/// 10 images and 5 MiB total). Local history never had those aggregate/count
/// limits; impose only its existing per-image bound and bounded full decode.
pub(crate) fn prepare_stored_images(images: &[RuntimeImageInput]) -> Result<Vec<ContentBlock>> {
prepare_images_with_limit(images, MAX_IMAGE_BYTES, None)
}
fn prepare_images_with_limit(
images: &[RuntimeImageInput],View on GitHub (pinned to 73e0f67d83)