run-llama/liteparse · error · std::io::Error

invalid RGB buffer length for

Error message

invalid RGB buffer length for {width}x{height}: expected {expected_len} bytes, got {}

What it means

rgb_image requires the byte slice to contain exactly width * height * 3 bytes (one RGB triple per pixel). When image_data.len() differs from the expected length, the buffer and the declared dimensions disagree, so the call is rejected with this InvalidInput error naming both expected and actual sizes. This is a strict contract check before constructing the RgbImage.

Solutions

  1. Convert the buffer to strict 3-bytes-per-pixel RGB before calling (drop the alpha channel, remove row stride/padding).
  2. Recompute width/height from the actual buffer (len/3, with a known aspect) so they match.
  3. Ensure the dimensions and the byte buffer come from the same decoded image.

Example fix

// before: RGBA buffer passed as RGB
let rgba = decoded.to_rgba8();
ocr.recognize_sync(rgba.as_raw(), decoded.width(), decoded.height())?;

// after: convert to RGB first
let rgb = DynamicImage::ImageRgba8(decoded.to_rgba8()).to_rgb8();
ocr.recognize_sync(rgb.as_raw(), rgb.width(), rgb.height())?;
Defensive patterns

Strategy: validation

Validate before calling

// Rust: assert RGB (3 bytes/pixel) buffer length matches dims
fn rgb_len_ok(data: &[u8], w: u32, h: u32) -> bool {
    data.len() == w as usize * h as usize * 3
}

Type guard

fn as_exact_rgb(data: &[u8], w: u32, h: u32)
    -> Option<&[u8]>
{
    let expected = (w as usize).checked_mul(h as usize)?.checked_mul(3)?;
    (data.len() == expected).then_some(data)
}

Prevention

When it happens

Trigger: Calling the OCR recognize path with a buffer whose length does not match width*height*3 — e.g. passing RGBA data (4 bytes/pixel) as RGB, passing grayscale data, or passing dimensions from a different image than the buffer.

Common situations: Mixing up RGBA and RGB buffers when piping decoded image data to OCR; OCR servers returning raw buffers with stride/padding; copying dimensions from one decoded image and bytes from another.

Related errors


AI-assisted analysis of run-llama/liteparse@22d2dd8cd7 (2026-09-08). Data as JSON: /api/errors/a4845a7dc8604ab5. Report an issue: GitHub.

Appendix: source

Thrown at crates/liteparse/src/ocr/oar.rs:277

    if width == 0 || height == 0 {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("invalid zero-sized RGB image: {width}x{height}"),
        ));
    }

    let expected_len = (width as usize)
        .checked_mul(height as usize)
        .and_then(|pixels| pixels.checked_mul(3))
        .ok_or_else(|| {
            io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("RGB image dimensions overflow: {width}x{height}"),
            )
        })?;

    if image_data.len() != expected_len {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!(
                "invalid RGB buffer length for {width}x{height}: expected {expected_len} bytes, got {}",
                image_data.len()
            ),
        ));
    }

    image::RgbImage::from_raw(width, height, image_data.to_vec()).ok_or_else(|| {
        io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("failed to construct RGB image from {width}x{height} buffer"),
        )
    })
}

fn region_to_result(region: oar_ocr::oarocr::TextRegion) -> Option<OcrResult> {
    let text = region.text?.trim().to_owned();

View on GitHub (pinned to 22d2dd8cd7)