bevyengine/bevy · error · FileTextureError

Error reading image file {path}: {error}.

Error message

Error reading image file {path}: {error}.

What it means

FileTextureError (image_loader.rs:276-281) is the path-annotated wrapper Bevy's ImageLoader attaches to every TextureError coming out of Image::from_buffer, plus the guess-format failures in Guess mode (image_loader.rs:215-224). Its Display is "Error reading image file {path}: {error}." where error is the underlying TextureError (bad mime/extension, image-crate decode failure, unsupported format, KTX2/DDS/Basis container issues). It exists so asset-failure logs identify which file failed, not just why.

Source

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

                    tile_height_pixels,
                } => image.create_stacked_array_from_2d_grid(
                    image.height() / tile_height_pixels,
                    image.width() / tile_width_pixels,
                )?,
            };
            return Ok(image);
        }
        Ok(image)
    }

    fn extensions(&self) -> &[&str] {
        Self::SUPPORTED_FILE_EXTENSIONS
    }
}

/// An error that occurs when loading a texture from a file.
#[derive(Error, Debug)]
#[error("Error reading image file {path}: {error}.")]
pub struct FileTextureError {
    error: TextureError,
    path: String,
}

View on GitHub (pinned to 396ca72708)

Solutions

  1. Parse both fields programmatically (FileTextureError { error, path } — both pub-accessible via the error source) and log path + inner TextureError together.
  2. Fix the inner cause per its variant: re-export corrupt files, correct extensions, enable features, or pick supported formats for the target GPU.
  3. Open the named file in an image viewer to confirm it is valid before re-importing.
  4. Add a CI step that loads every image asset and fails on any FileTextureError so broken art never merges.

Example fix

// before
error!("texture failed: {err}"); // no file name in context

// after — extract the path from FileTextureError
fn diagnose(err: &ImageLoaderError) {
    if let ImageLoaderError::FileTexture(fe) = err {
        error!("asset {} failed: {}", fe.path, fe.error);
    }
}
Defensive patterns

Strategy: try-catch

Try / catch

match Image::from_buffer(&bytes, image_type, formats, true, sampler, usage) {
    Err(e) => {
        let fe = FileTextureError { error: e, path: path.to_string() };
        error!("{fe}"); // prints path + inner cause
    }
    Ok(img) => { /* ... */ }
}

Prevention

When it happens

Trigger: ImageLoader::load constructs it at image_loader.rs:215-224 when image::guess_format fails or the guessed format has no Bevy ImageFormat, and at 236-239 when Image::from_buffer errors; it then surfaces through ImageLoaderError::FileTexture in AssetLoadFailedEvent<Image> and logs.

Common situations: Browsing engine logs for why a texture shows as magenta/missing; CI asset validation; diagnosing one broken file among a large imported texture set — the path field points at the culprit.

Related errors


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