Hmbown/CodeWhale · error
invalid image content or decode allocation limit
Error message
invalid image content or decode allocation limit
What it means
After the dimension check passed, the actual decode of pixel data failed — the image content is corrupt or decoding would exceed the allocation limit set via reader.limits(). The dimension probe succeeding but the full decode failing usually means damaged compressed data (truncated IDAT/stream) rather than a bad header.
Solutions
- Re-export the image with a known-good encoder to repair the stream.
- Convert to a common format (PNG or JPEG) before attaching: `magick convert in.webp out.png`.
- Downscale the image so full decode fits within the allocation limit.
Example fix
// before let img = image::load_from_memory(&truncated_bytes)?; // corrupt stream // after let img = image::load_from_memory(&re_encoded_png_bytes)?;
Defensive patterns
Strategy: validation
Validate before calling
// Pre-decode integrity probe
let probe = image::io::Reader::new(Cursor::new(&bytes)).with_guessed_format()?;
let dims = probe.into_dimensions()?;
let est = dims.0 as u64 * dims.1 as u64 * 4; // rough RGBA size
if est > decode_budget { bail!("image too large to decode; downscale first"); } Try / catch
// Rust
match decode_and_guard_image(bytes, limits) {
Ok(decoded) => use_image(decoded),
Err(e) if e.to_string().contains("decode allocation") => {
let fixed = re_encode_downscaled(&bytes)?;
use_image(decode_and_guard_image(fixed, limits)?);
}
Err(e) => return Err(e),
} Prevention
- Re-encode images from a trusted source before attaching rather than forwarding raw bytes.
- Pre-downscale large images on the producer side.
- Treat network-fetched images as suspect: verify content length against header dimensions.
When it happens
Trigger: decode_and_guard_image is called and reader.decode() fails on otherwise dimension-valid bytes: truncated JPEG/PNG streams, corrupt pixel data, or content whose decode buffer exceeds the configured memory limits.
Common situations: Interrupted uploads that pass a partial header check; images recompressed by buggy tools; animated or very large images whose full frame allocation exceeds the decode limit.
Related errors
- invalid image header or decompression bomb guard
- image base64 is not canonical
- image dimensions exceed the decompression bomb guard…
- image exceeds the MiB limit
- image has invalid base64
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/2a91e14cb3c070f2.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/image_attach.rs:98
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,
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,View on GitHub (pinned to 73e0f67d83)