Hmbown/CodeWhale · error

image dimensions exceed the decompression bomb guard…

Error message

image dimensions exceed the decompression bomb guard; downscale or crop first

What it means

An image's declared pixel dimensions (width x height from the header, before full decode) exceed the decompression-bomb guard: the pixel count exceeds MAX_IMAGE_PIXELS or a single dimension exceeds MAX_IMAGE_DIMENSION. The library checks dimensions from the header first so hostile or accidental gigantic images are rejected before allocating decode memory.

Solutions

  1. Downscale or crop the image so both dimensions and total pixels are under the guard before attaching.
  2. Re-encode as a reasonably sized JPEG/PNG (e.g. max side ~2048px) with an image tool or ImageMagick.
  3. If legitimate large images are common, pre-process them at ingestion rather than at attach time.
  4. For programmatic use, check width*height against MAX_IMAGE_PIXELS before calling the attach API.

Example fix

// before
magick input.png attach.png            # keeps 18000x12000
// after
magick input.png -resize 2048x2048\> attach.png
Defensive patterns

Strategy: validation

Validate before calling

fn header_dims_ok(bytes: &[u8]) -> bool {
    ImageReader::new(Cursor::new(bytes))
        .into_dimensions()
        .map(|(w, h)| {
            u64::from(w) * u64::from(h) <= MAX_IMAGE_PIXELS
                && w <= MAX_IMAGE_DIMENSION && h <= MAX_IMAGE_DIMENSION
        })
        .unwrap_or(false)
}

Type guard

fn guarded_dimensions(reader: &ImageReader<Cursor<&[u8]>>) -> Option<(u32, u32)> {
    reader.into_dimensions().ok().filter(|(w, h)| {
        u64::from(*w) * u64::from(*h) <= MAX_IMAGE_PIXELS
    })
}

Try / catch

match prepare_tool_image_bytes(&bytes) {
    Err(e) if e.to_string().contains("decompression bomb guard") => {
        eprintln!("image too large; downscale to <= {} px per side", MAX_IMAGE_DIMENSION); }
    other => other?,
}

Prevention

When it happens

Trigger: decode_and_guard_image is reached with bytes whose header advertises dimensions over the guard — e.g. a 20000x20000 PNG, a panorama, a scaled-up screenshot, or a crafted bomb image — via prepare_runtime_images, prepare_stored_images, prepare_tool_image_bytes, or process_media_file.

Common situations: Attaching a high-resolution camera panorama or scanned poster; a malicious upload designed to exhaust memory; a resized image saved with huge canvas dimensions but tiny content; scientific/medical images that legitimately exceed the dimension 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


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/eb98f4045a3256d8. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/image_attach.rs:92

pub(crate) fn decode_and_guard_image(bytes: &[u8]) -> Result<(DynamicImage, u32, u32)> {
    let limits = || {
        let mut limits = Limits::default();
        limits.max_alloc = Some(MAX_DECODE_ALLOC_BYTES);
        limits.max_image_width = Some(MAX_IMAGE_DIMENSION);
        limits.max_image_height = Some(MAX_IMAGE_DIMENSION);
        limits
    };
    let mut reader = ImageReader::new(Cursor::new(bytes)).with_guessed_format()?;
    reader.limits(limits());
    let (width, height) = reader
        .into_dimensions()
        .map_err(|_| anyhow::anyhow!("invalid image header or decompression bomb guard"))?;
    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,

View on GitHub (pinned to 73e0f67d83)