{"record":{"id":"2a91e14cb3c070f2","repo":"Hmbown/CodeWhale","slug":"invalid-image-content-or-decode-allocation-limit","errorCode":null,"errorMessage":"invalid image content or decode allocation limit","messagePattern":"invalid image content or decode allocation limit","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/image_attach.rs","lineNumber":98,"sourceCode":"        limits.max_image_height = Some(MAX_IMAGE_DIMENSION);\n        limits\n    };\n    let mut reader = ImageReader::new(Cursor::new(bytes)).with_guessed_format()?;\n    reader.limits(limits());\n    let (width, height) = reader\n        .into_dimensions()\n        .map_err(|_| anyhow::anyhow!(\"invalid image header or decompression bomb guard\"))?;\n    if u64::from(width) * u64::from(height) > MAX_IMAGE_PIXELS\n        || width > MAX_IMAGE_DIMENSION\n        || height > MAX_IMAGE_DIMENSION\n    {\n        bail!(\"image dimensions exceed the decompression bomb guard; downscale or crop first\");\n    }\n    let mut reader = ImageReader::new(Cursor::new(bytes)).with_guessed_format()?;\n    reader.limits(limits());\n    let decoded = reader\n        .decode()\n        .map_err(|_| anyhow::anyhow!(\"invalid image content or decode allocation limit\"))?;\n    Ok((decoded, width, height))\n}\n\n/// Validate untrusted inline input before route selection or durable admission.\n/// Return the existing provider-neutral history representation; no file is opened.\npub(crate) fn prepare_runtime_images(images: &[RuntimeImageInput]) -> Result<Vec<ContentBlock>> {\n    if images.len() > MAX_RUNTIME_IMAGES {\n        bail!(\"images exceed the {MAX_RUNTIME_IMAGES} attachment limit\");\n    }\n    prepare_images_with_limit(\n        images,\n        MAX_RUNTIME_IMAGE_BYTES,\n        Some(MAX_RUNTIME_IMAGE_TOTAL_BYTES),\n    )\n}\n\n/// Internal Engine/history input retains the established local 5 MiB ceiling.\n/// Network callers must first pass `prepare_runtime_images` (4 MiB per image,","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/image_attach.rs#L80-L116","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet img = image::load_from_memory(&truncated_bytes)?; // corrupt stream\n\n// after\nlet img = image::load_from_memory(&re_encoded_png_bytes)?;","handlingStrategy":"validation","validationCode":"// Pre-decode integrity probe\nlet probe = image::io::Reader::new(Cursor::new(&bytes)).with_guessed_format()?;\nlet dims = probe.into_dimensions()?;\nlet est = dims.0 as u64 * dims.1 as u64 * 4; // rough RGBA size\nif est > decode_budget { bail!(\"image too large to decode; downscale first\"); }","typeGuard":null,"tryCatchPattern":"// Rust\nmatch decode_and_guard_image(bytes, limits) {\n    Ok(decoded) => use_image(decoded),\n    Err(e) if e.to_string().contains(\"decode allocation\") => {\n        let fixed = re_encode_downscaled(&bytes)?;\n        use_image(decode_and_guard_image(fixed, limits)?);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["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."],"tags":["image","decoding","memory-limit"],"backgroundTag":"image-decode-failed","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}