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
- Enable the decoding features in Cargo.toml: tauri = { version = "2", features = ["image-png", "image-ico"] }
- Or change the frontend payload to raw RGBA: { rgba: Uint8Array, width, height }
- Convert images to RGBA on the JS side with the transformImage API before invoking
- 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
- Declare features = ["image-png", "image-ico"] explicitly rather than relying on defaults or unification
- Send RGBA payloads from JS when in doubt — they convert under every feature set
- Re-check tauri's feature list after upgrades or after trimming default-features
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
- failed to parse icon {}: {}
- The `{}` dependency features on the `Cargo.toml` file
- unsupported ColorType: {:?}
AI-assisted analysis of tauri-apps/tauri@52e4b6e71d (2026-08-20).
Data as JSON: /api/errors/0d5dd2df535b5e45.
Report an issue: GitHub.