Hmbown/CodeWhale · error

invalid image header or decompression bomb guard

Error message

invalid image header or decompression bomb guard

What it means

The image decoder could not read the image's dimensions, meaning the header is malformed or the format's declared size tripped the decoder's configured memory limits (the decompression-bomb guard applied via reader.limits()). This is a fail-fast check before the pixel-count guard runs.

Solutions

  1. Verify the bytes are a complete, valid image; re-export or re-download the file.
  2. Re-encode the image (e.g. `magick convert in.png out.png`) to produce a clean header.
  3. Downscale or crop the image so its header-declared dimensions fit within the configured limits.

Example fix

// before
let bytes = std::fs::read("screenshot.png.partial")?; // truncated

// after
let bytes = std::fs::read("screenshot.png")?; // complete file; header parses
Defensive patterns

Strategy: validation

Validate before calling

let fmt = image::guess_format(&bytes)?; // fails early on non-image bytes
let (w, h) = image::io::Reader::new(Cursor::new(&bytes)).with_guessed_format()?.into_dimensions()?;
assert!(w > 0 && h > 0, "truncated or corrupt image header");

Try / catch

// Rust
match decode_and_guard_image(bytes, limits) {
    Ok((img, w, h)) => attach(img),
    Err(e) if e.to_string().contains("invalid image header") => {
        eprintln!("attachment is not a readable image; re-export it");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling decode_and_guard_image (via prepare_images_with_limit, prepare_tool_image_bytes, valid_tool_image, process_media_file, or read_media_over_budget_failure_names_conversion_recipe) with bytes that ImageReader::with_guessed_format + into_dimensions cannot parse: truncated files, non-image data, or headers claiming dimensions beyond the configured limits.

Common situations: Attaching a corrupted or partially downloaded image; pasting base64 that decodes to HTML/text rather than image data; a legitimately huge image whose header allocations exceed the decoder limits; wrong file extension or mis-detected format.

Related errors


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

Appendix: source

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

/// Maximum total pixels admitted before decoding is aborted (~33.5 megapixels).
pub const MAX_IMAGE_PIXELS: u64 = 33_554_432;

/// Memory allocation limit for image decoding (64 MiB).
pub const MAX_DECODE_ALLOC_BYTES: u64 = 64 * 1024 * 1024;

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 {

View on GitHub (pinned to 73e0f67d83)