{"record":{"id":"b84e15764740fd32","repo":"Hmbown/CodeWhale","slug":"image-exceeds-the-mib-limit","errorCode":null,"errorMessage":"image {} exceeds the {} MiB limit","messagePattern":"image (.+?) exceeds the (.+?) MiB limit","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/image_attach.rs","lineNumber":134,"sourceCode":"/// Network callers must first pass `prepare_runtime_images` (4 MiB per image,\n/// 10 images and 5 MiB total). Local history never had those aggregate/count\n/// limits; impose only its existing per-image bound and bounded full decode.\npub(crate) fn prepare_stored_images(images: &[RuntimeImageInput]) -> Result<Vec<ContentBlock>> {\n    prepare_images_with_limit(images, MAX_IMAGE_BYTES, None)\n}\n\nfn prepare_images_with_limit(\n    images: &[RuntimeImageInput],\n    per_image_limit: usize,\n    total_limit: Option<usize>,\n) -> Result<Vec<ContentBlock>> {\n    let mut total = 0usize;\n    images\n        .iter()\n        .enumerate()\n        .map(|(index, image)| {\n            if image.data_base64.len() > per_image_limit.div_ceil(3) * 4 {\n                bail!(\n                    \"image {} exceeds the {} MiB limit\",\n                    index + 1,\n                    per_image_limit / (1024 * 1024)\n                );\n            }\n            let bytes = STANDARD\n                .decode(&image.data_base64)\n                .map_err(|_| anyhow::anyhow!(\"image {} has invalid base64\", index + 1))?;\n            if bytes.len() > per_image_limit {\n                bail!(\n                    \"image {} exceeds the {} MiB limit\",\n                    index + 1,\n                    per_image_limit / (1024 * 1024)\n                );\n            }\n            total = total.saturating_add(bytes.len());\n            if total_limit.is_some_and(|limit| total > limit) {\n                bail!(\"images exceed the 5 MiB total limit\");","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/image_attach.rs#L116-L152","documentation":"prepare_images_with_limit checks each image's base64 payload length against the per-image limit before decoding; since base64 inflates bytes by 4/3, the pre-decode check uses per_image_limit.div_ceil(3) * 4. This bail fires when the base64 string itself is already too long for the configured per-image MiB budget.","triggerScenarios":"Calling prepare_runtime_images or prepare_stored_images with an image whose data_base64 length exceeds per_image_limit.div_ceil(3)*4 — e.g. a >5 MiB (or per-limit) image supplied as base64, caught before any decode work.","commonSituations":"Attaching a raw camera photo or high-res screenshot that exceeds the MiB cap; reading a large file and base64-encoding it without size checks; a caller passing base64 from another (larger-limit) system.","solutions":["Compress or resize the image before encoding so its base64 fits the limit.","Convert to JPEG with reasonable quality — typically the biggest win for photos.","Check data_base64.len() against the limit in the caller and downsize large images first.","Document the byte cap where images enter the system so oversized ones are rejected earlier with a better message."],"exampleFix":"// before\nlet b64 = STANDARD.encode(&huge_png_bytes);  // > 4/3 * 5MiB\nattach(RuntimeImageInput { data_base64: b64, .. })?;\n// after\nlet small = resize_to_max_side(&huge_png_bytes, 2048)?;\nattach(RuntimeImageInput { data_base64: STANDARD.encode(&small), .. })?;","handlingStrategy":"validation","validationCode":"fn b64_fits(data_base64: &str, per_image_limit: usize) -> bool {\n    data_base64.len() <= per_image_limit.div_ceil(3) * 4\n}","typeGuard":null,"tryCatchPattern":"match prepare_runtime_images(&images) {\n    Err(e) if e.to_string().contains(\"MiB limit\") => {\n        eprintln!(\"shrink images to <= {} MiB each before attaching\", MAX_RUNTIME_IMAGE_BYTES / (1024*1024)); }\n    other => other?,\n}","preventionTips":["Check base64 length before calling the attach API","Resize/compress large images at ingestion","Prefer JPEG for photos to stay well under the cap"],"tags":["image","limit","base64"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T16:17:23.217Z"}