tauri-apps/tauri · error · std::io::Error

expected RGBA image data, found {}

Error message

expected RGBA image data, found {}

What it means

JsImage is the untagged deserialization target for image values sent from JavaScript (e.g. via transformImage). into_img converts it to an Image: the Path and Bytes variants need actual image decoding, which is only compiled in when the image-ico and/or image-png cargo features are enabled on tauri. With both features off, only the Rgba { rgba, width, height } variant converts, and Path/Bytes inputs fail with InvalidInput: 'expected RGBA image data, found a file path / raw bytes'.

Source

Thrown at crates/tauri/src/image/mod.rs:215

  /// the webview resources table.
  pub fn into_img(self, resources_table: &ResourceTable) -> crate::Result<Arc<Image<'_>>> {
    match self {
      Self::Resource(rid) => resources_table.get::<Image<'static>>(rid),
      #[cfg(any(feature = "image-ico", feature = "image-png"))]
      Self::Path(path) => Image::from_path(path).map(Arc::new),

      #[cfg(any(feature = "image-ico", feature = "image-png"))]
      Self::Bytes(bytes) => Image::from_bytes(&bytes).map(Arc::new),

      Self::Rgba {
        rgba,
        width,
        height,
      } => Ok(Arc::new(Image::new_owned(rgba, width, height))),

      #[cfg(not(any(feature = "image-ico", feature = "image-png")))]
      _ => Err(
        std::io::Error::new(
          std::io::ErrorKind::InvalidInput,
          format!(
            "expected RGBA image data, found {}",
            match self {
              JsImage::Path(_) => "a file path",
              JsImage::Bytes(_) => "raw bytes",
              _ => unreachable!(),
            }
          ),
        )
        .into(),
      ),
    }
  }
}

View on GitHub (pinned to 52e4b6e71d)

Solutions

  1. Enable the decoding features in Cargo.toml: tauri = { version = "2", features = ["image-png", "image-ico"] }
  2. Or change the frontend payload to raw RGBA: { rgba: Uint8Array, width, height }
  3. Convert images to RGBA on the JS side with the transformImage API before invoking
  4. Declare the features explicitly in your own Cargo.toml so feature unification cannot drop them

Example fix

# before (Cargo.toml)
tauri = { version = "2", default-features = false }
# after
tauri = { version = "2", default-features = false, features = ["image-png", "image-ico"] }
Defensive patterns

Strategy: type-guard

Validate before calling

// frontend: send the shape that works even without image features
const image = { rgba: Array.from(rgbaBytes), width, height }; // JsImage::Rgba
await invoke('set_tray_icon', { image });

Type guard

// Rust: only these variants can convert without image-ico/image-png features
fn converts_without_image_features(img: &tauri::image::JsImage) -> bool {
    matches!(
        img,
        tauri::image::JsImage::Rgba { .. } | tauri::image::JsImage::Resource(_)
    )
}

Try / catch

match js_image.into_img(&resources_table) {
    Ok(image) => { /* use image */ }
    Err(e) => {
        // path/bytes rejected: enable tauri features image-png/image-ico,
        // or make the frontend send { rgba, width, height }
        log::warn!("image rejected: {e}");
    }
}

Prevention

When it happens

Trigger: A Rust API that accepts JsImage and calls into_img (tray icons, window icons, custom plugins), built without tauri's image-ico and image-png features, while the frontend sends a file-path string or raw encoded bytes instead of { rgba, width, height }.

Common situations: Slimming default-features to cut binary size and silently dropping the image codecs; JS code passing a path string out of convenience; version upgrades where feature sets changed; a dependency disabling tauri default features via feature unification.

Related errors


AI-assisted analysis of tauri-apps/tauri@52e4b6e71d (2026-08-20). Data as JSON: /api/errors/0d5dd2df535b5e45. Report an issue: GitHub.