bevyengine/bevy · error · TextureAccessError
image data is not initialized
Error message
image data is not initialized
What it means
TextureAccessError::Uninitialized is returned by Image::pixel_bytes and Image::pixel_bytes_mut (crates/bevy_image/src/image.rs:1702, 1714) when the Image's data field (pub data: Option<Vec<u8>>) is None. That means there is no CPU-side copy: either the image was created with Image::new_uninit and never filled, or it was loaded with RenderAssetUsages::RENDER_WORLD so Bevy dropped the CPU bytes after uploading to the GPU. The variant's doc comment points to RenderAssetUsages for controlling when data is moved.
Source
Thrown at crates/bevy_image/src/image.rs:2279
/// how to retain it if necessary.
#[error("image data is not initialized")]
Uninitialized,
/// The texture's dimension was different than indicated by the accessor used.
#[error("attempt to access texture with different dimension")]
WrongDimension,
}
/// An error that occurs when loading a texture.
#[derive(Error, Debug)]
pub enum TextureError {
/// Image MIME type is invalid.
#[error("invalid image mime type: {0}")]
InvalidImageMimeType(String),
/// Image extension is invalid.
#[error("invalid image extension: {0}")]
InvalidImageExtension(String),
/// Failed to load an image.
#[error("failed to load an image: {0}")]
ImageError(#[from] image::ImageError),
/// Texture format isn't supported.
#[error("unsupported texture format: {0}")]
UnsupportedTextureFormat(String),
/// Supercompression isn't supported.
#[error("supercompression not supported: {0}")]
SuperCompressionNotSupported(String),
/// Failed to decompress an image.
#[error("failed to decompress an image: {0}")]
SuperDecompressionError(String),
/// Invalid data.
#[error("invalid data: {0}")]
InvalidData(String),
/// Transcode error.
#[error("transcode error: {0}")]
TranscodeError(String),
/// Format requires transcoding.
#[error("format requires transcoding: {0:?}")]View on GitHub (pinned to 221e52ae32)
Solutions
- Load the asset with the default RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD so the CPU copy survives the GPU upload.
- If you used Image::new_uninit, fill it first (Image::new, Image::new_fill, or a write via pixel_bytes_mut) before any read.
- If the handle already points at a RENDER_WORLD-only asset, re-load the source file from the AssetServer or keep a second MAIN_WORLD copy reserved for CPU reads.
Example fix
// before — CPU data is dropped after upload
server.load_with_settings("tex.png", |s: &mut ImageLoaderSettings| {
s.asset_usage = RenderAssetUsages::RENDER_WORLD;
});
let bytes = image.pixel_bytes(UVec3::ZERO)?; // Err(Uninitialized)
// after — retain the CPU copy
s.asset_usage = RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD; Defensive patterns
Strategy: validation
Validate before calling
// before pixel_bytes / pixel_bytes_mut / get_color_at:
if image.data.as_ref().is_some_and(|d| !d.is_empty()) {
let bytes = image.pixel_bytes(UVec3::new(x, y, 0))?;
} Type guard
fn has_cpu_data(image: &Image) -> bool {
image.data.as_ref().is_some_and(|d| !d.is_empty())
} Try / catch
match image.pixel_bytes(coords) {
Ok(bytes) => { /* ... */ }
Err(TextureAccessError::Uninitialized) => {
// re-load with MAIN_WORLD usage or keep a CPU copy
}
Err(e) => warn!("pixel access failed: {e}"),
} Prevention
- Keep RenderAssetUsages::MAIN_WORLD in asset_usage for any texture you will read or serialize.
- Only use RenderAssetUsages::RENDER_WORLD alone for pure GPU assets you never touch on CPU.
- Fill new_uninit images with new_fill or pixel writes before reading them.
When it happens
Trigger: Calling pixel_bytes/pixel_bytes_mut (or the get_color_at*/set_color_at* accessors built on them) on an Image whose data is None — created via Image::new_uninit without a subsequent write, or loaded through ImageLoaderSettings with asset_usage = RenderAssetUsages::RENDER_WORLD (CPU copy freed after GPU upload).
Common situations: Games that set RENDER_WORLD-only usage to halve texture memory, then later try to read pixels for screenshots, picking, or serialization; images created with new_uninit awaiting an async fill; code that assumes texture data is always resident on CPU after load.
Related errors
- Image has no texture data
- Could not load texture file: {0}
- Error reading image file {path}: {error}.
- Conversion into dynamic image not supported for {0:?}.
- Failed to convert into {0:?}.
AI-assisted analysis of bevyengine/bevy@221e52ae32 (2026-08-20).
Data as JSON: /api/errors/4ab72f13411250e0.
Report an issue: GitHub.