bevyengine/bevy · error · ImageLoaderError
Invalid array layout: {0}
Error message
Invalid array layout: {0} What it means
ImageLoaderError::ArrayLayout (image_loader.rs:185-186) wraps TextureReinterpretationError, raised when ImageLoaderSettings::array_layout reinterprets a stacked 2D image as a texture array (image_loader.rs:245-265). The inner variants (image.rs:2200-2246) name the exact problem: WrongDimension (not a 2D image), InvalidLayerCount (already layered), HeightNotDivisibleByLayers, GridHeightNotDivisibleByTileHeight/GridWidthNotDivisibleByTileWidth, NotEnoughLayers, IncompatibleSizes, and InvalidTextureFormat ("Is it compressed?"). It fires after a successful decode, while slicing the pixel data into layers.
Source
Thrown at crates/bevy_image/src/image_loader.rs:185
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<'_>,
) -> Result<Image, Self::Error> {
let mut bytes = Vec::new();
reader.read_to_end(&mut bytes).await?;
let image_type = match settings.format {
ImageFormatSetting::FromExtension => {
// use the file extension for the image typeView on GitHub (pinned to 396ca72708)
Solutions
- Make the sheet geometry exact: height must be rows * row_height and the grid must divide evenly into tiles (verify width % tile_w == 0 and height % tile_h == 0).
- Double-check the RowCount/RowHeight/GridCount/GridSize settings — swapped rows/columns is the most common mistake.
- Ensure the source image is a plain single-layer 2D uncompressed image (PNG), not an already-layered or compressed file.
- For RowHeight/GridSize, remember Bevy divides image.height() by the value you give — pick the number that yields an integer layer count >= 2 (NotEnoughLayers otherwise).
Example fix
// before — sheet is 256x252, rows = 4 (252 is not divisible)
// textures/particles.meta: "loader": { "settings": { "array_layout": { "type": "row_count", "rows": 4 } } }
// after — author the sheet at an exact multiple (4 * 64 = 256) and keep the same meta
// re-export particles.png at 256x256 Defensive patterns
Strategy: validation
Validate before calling
// verify the sheet divides evenly before enabling array_layout
let (w, h) = (image.width(), image.height());
let layers = h / row_height;
assert!(h % row_height == 0 && layers >= 2, "height {h} not divisible by {row_height}");
assert!(w % tile_w == 0 && h % tile_h == 0, "grid must divide evenly"); Type guard
fn array_layout_ok(image: &Image, rows: u32) -> bool {
image.texture_descriptor.dimension == TextureDimension::D2
&& image.texture_descriptor.size.depth_or_array_layers == 1
&& image.height() % rows == 0
&& image.height() / rows >= 2
&& !image.is_compressed()
} Try / catch
// array_layout is loader-side; failures arrive via events:
if let ImageLoaderError::ArrayLayout(e) = &*ev.error {
error!("array reinterpretation failed: {e}"); // fix sheet dimensions or meta settings
} Prevention
- Author sprite stacks at exact multiples of the row/tile size (authoring templates with fixed grid sizes helps).
- Double-check rows vs columns order in GridCount meta.
- Only apply array_layout to single-layer uncompressed 2D images.
When it happens
Trigger: Setting array_layout in an image's .meta or via load_with_settings: RowCount { rows } on a sheet whose height is not divisible by rows; RowHeight/GridCount on a grid that does not tile evenly (image_loader.rs:248-264); an already-layered or 3D source; a compressed source format (InvalidTextureFormat).
Common situations: Texture2DArray sprite sheets authored with off-by-one pixel sizes (e.g. 256x252 for 4 rows of 64); grid layouts declared with swapped columns/rows; applying array_layout meta to files that were already exported as arrays.
Related errors
- Failed to load image bytes: {0}
- Could not load texture file: {0}
- Error reading image file {path}: {error}.
- Field name should exist
- Field name should be a valid tuple index
AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20).
Data as JSON: /api/errors/f14a2fe6d45e1719.
Report an issue: GitHub.