emilk/egui · error
Failed to create image
Error message
Failed to create image
What it means
texture_to_image() strips the per-row padding from a GPU buffer copy and hands the tightly packed RGBA bytes to image::RgbaImage::from_raw, expecting the created image. from_raw returns None whenever data.len() != width * height * 4, and the code panics with "Failed to create image". This is an internal size invariant: the BufferDimensions bookkeeping must exactly match the texture's byte layout.
Source
Thrown at crates/egui_kittest/src/texture_to_image.rs:70
device
.poll(wgpu::PollType::Wait {
submission_index: Some(submission_index),
timeout: Some(WAIT_TIMEOUT),
})
.expect("Failed to poll device");
receiver.recv().unwrap().unwrap();
let buffer_slice = output_buffer.slice(..);
let data = buffer_slice
.get_mapped_range()
.expect("Failed to get mapped range");
let data = data
.chunks_exact(buffer_dimensions.padded_bytes_per_row)
.flat_map(|row| row.iter().take(buffer_dimensions.unpadded_bytes_per_row))
.copied()
.collect::<Vec<_>>();
RgbaImage::from_raw(texture.width(), texture.height(), data).expect("Failed to create image")
}
struct BufferDimensions {
height: usize,
unpadded_bytes_per_row: usize,
padded_bytes_per_row: usize,
}
impl BufferDimensions {
fn new(width: usize, height: usize) -> Self {
let bytes_per_pixel = size_of::<u32>();
let unpadded_bytes_per_row = width * bytes_per_pixel;
let align = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT as usize;
let padded_bytes_per_row_padding = (align - unpadded_bytes_per_row % align) % align;
let padded_bytes_per_row = unpadded_bytes_per_row + padded_bytes_per_row_padding;
Self {
height,
unpadded_bytes_per_row,View on GitHub (pinned to 441971a776)
Solutions
- Assert data.len() == texture.width() * texture.height() * 4 before from_raw and print both numbers to find the accounting bug
- Verify padded_bytes_per_row is computed as the wgpu-mandated stride ((bytes_per_row + 255) / 256 * 256), matching the buffer mapping
- Recreate the texture/view with TextureFormat::Rgba8Unorm (or convert the copy) before snapshotting
- Replace the expect with a match that returns a descriptive Result so the size mismatch is reported, not panicked
Example fix
// before
RgbaImage::from_raw(texture.width(), texture.height(), data).expect("Failed to create image")
// after
let expected = texture.width() as usize * texture.height() as usize * 4;
assert_eq!(data.len(), expected, "texture byte count mismatch: {} vs {}", data.len(), expected);
RgbaImage::from_raw(texture.width(), texture.height(), data)
.expect("Failed to create image: byte count does not match width*height*4") Defensive patterns
Strategy: validation
Validate before calling
let expected = (texture.width() as usize) * (texture.height() as usize) * 4;
assert_eq!(data.len(), expected, "texture bytes {} != {} (w={}, h={})", data.len(), expected, texture.width(), texture.height()); Prevention
- Always snapshot textures in Rgba8Unorm (or convert first); other formats change bytes-per-pixel
- Compute padded_bytes_per_row with wgpu's 256-byte alignment rule: (bpr + 255) / 256 * 256
- Recompute BufferDimensions whenever width/height/format changes
- Assert byte-count invariants in tests instead of relying on the final expect
When it happens
Trigger: A texture whose bytes-per-pixel is not 4 (e.g. BGRA/RGB formats) fed through the RGBA4 assumption; a mismatch between buffer_dimensions.padded_bytes_per_row used in chunks_exact and the actual buffer row stride returned by the wgpu copy; width/height changed after the buffer size was computed.
Common situations: kittest snapshot tests capturing non-Rgba8Unorm textures; GPU adapters that report a different buffer row alignment (256-byte requirement) than the calculated padded_bytes_per_row; downscaling or resizing textures in a harness without recomputing BufferDimensions.
Related errors
- Failed to create render state
- Failed to create staging buffer for index data. Index count:
- Failed to create staging buffer for vertex data. Vertex coun
- {err}
- {err}
AI-assisted analysis of emilk/egui@441971a776 (2026-09-12).
Data as JSON: /api/errors/fde283748147fe16.
Report an issue: GitHub.