bevyengine/bevy · error · ImageLoaderError

Failed to load image bytes: {0}

Error message

Failed to load image bytes: {0}

What it means

ImageLoaderError::Io (image_loader.rs:179-180) wraps a std::io::Error raised by `reader.read_to_end(&mut bytes).await?` at image_loader.rs:200 — the very first step of ImageLoader::load, before any decoding. It means the asset source could not deliver the file's bytes: file missing, permission denied, path invalid, or an embedded/filesystem/custom asset source mismatch. It is Bevy's asset-pipeline-level IO error for images, converted into the loader's error type via #[from].

Source

Thrown at crates/bevy_image/src/image_loader.rs:179

impl Default for ImageLoaderSettings {
    fn default() -> Self {
        Self {
            format: ImageFormatSetting::default(),
            texture_format: None,
            is_srgb: true,
            sampler: ImageSampler::Default,
            asset_usage: RenderAssetUsages::default(),
            array_layout: None,
        }
    }
}

/// An error when loading an image using [`ImageLoader`].
#[non_exhaustive]
#[derive(Debug, Error)]
pub enum ImageLoaderError {
    /// An error occurred while trying to load the image bytes.
    #[error("Failed to load image bytes: {0}")]
    Io(#[from] std::io::Error),
    /// An error occurred while trying to decode the image bytes.
    #[error("Could not load texture file: {0}")]
    FileTexture(#[from] FileTextureError),
    /// An error occurred while trying to interpret the image bytes as an array texture.
    #[error("Invalid array layout: {0}")]
    ArrayLayout(#[from] TextureReinterpretationError),
}

impl AssetLoader for ImageLoader {
    type Asset = Image;
    type Settings = ImageLoaderSettings;
    type Error = ImageLoaderError;
    async fn load(
        &self,
        reader: &mut dyn Reader,
        settings: &ImageLoaderSettings,
        load_context: &mut LoadContext<'_>,

View on GitHub (pinned to 396ca72708)

Solutions

  1. Verify the exact path (case-sensitive) exists under the configured asset root (default assets/).
  2. For mobile/embedded targets, rebuild/re-copy the asset bundle so the file is included.
  3. Handle AssetLoadFailedEvent<Image> (or check the Handle's loading state) and fall back to a placeholder texture instead of assuming success.
  4. If it happens during hot-reload only, treat it as transient: the watcher will re-load once the write finishes.

Example fix

// before — file is actually Hero.PNG on disk
let handle = server.load("textures/hero.png"); // ImageLoaderError::Io(NotFound)

// after — use the real path and react to failures
let handle = server.load("textures/Hero.PNG");
// system that reacts:
fn on_load_failed(mut ev: EventReader<AssetLoadFailedEvent<Image>>) {
    for ev in ev.read() {
        error!("image failed: {} ({:?})", ev.path, ev.error); // includes Io errors
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the asset exists before requesting it (filesystem source)
let path = std::path::Path::new("assets/textures/hero.png");
if !path.exists() {
    warn!("missing asset {path:?}");
    return placeholder_handle();
}

Try / catch

fn on_image_failed(mut ev: EventReader<AssetLoadFailedEvent<Image>>, mut commands: Commands) {
    for ev in ev.read() {
        if let ImageLoaderError::Io(e) = &*ev.error {
            match e.kind() {
                std::io::ErrorKind::NotFound => error!("asset {} not found", ev.path),
                _ => error!("asset io error on {}: {e}", ev.path),
            }
            // spawn placeholder / queue retry after fix
        }
    }
}

Prevention

When it happens

Trigger: server.load("textures/hero.png") when the file does not exist under the assets root; permissions blocking reads in a packaged build; an Android/iOS embedded-asset source missing the file because it was added after the last packaging; watching a file being rewritten (transient read failure during hot reload).

Common situations: Path casing mismatches on case-sensitive filesystems (Hero.PNG vs hero.png on Linux/Android); assets folder misconfigured via AssetPlugin::file_path; files not added to the mobile bundle; network/HTTP asset sources returning IO errors.

Related errors


AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20). Data as JSON: /api/errors/3962aae9f0805881. Report an issue: GitHub.