bevyengine/bevy · critical
Texture format is not supported by the pipeline
Error message
Texture format is not supported by the pipeline
What it means
`MeshPipelineKey::from_target_format` (crates/bevy_pbr/src/render/mesh.rs:3168) encodes the view's color target format into a 5-bit field of the pipeline key using `texture_format_to_code` (crates/bevy_render/src/view/mod.rs:106). That function only maps WebGPU 'plain' renderable+blendable formats (R8/Rg8/Rgba8 unorm/snorm/srgb, Bgra8 variants, R16/Rg16/Rgba16 float+unorm+snorm, R32Float/Rg32Float/Rgba32Float, Rgb10a2Unorm, Rg11b10Ufloat). Any other format returns `None` and the `.expect` panics.
Source
Thrown at crates/bevy_pbr/src/render/mesh.rs:3169
const SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS: u64 =
Self::VIEW_PROJECTION_MASK_BITS.count_ones() as u64 + Self::VIEW_PROJECTION_SHIFT_BITS;
const COLOR_TARGET_FORMAT_MASK_BITS: u64 = view::COLOR_TARGET_FORMAT_MASK_BITS as u64;
const COLOR_TARGET_FORMAT_SHIFT_BITS: u64 = Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_MASK_BITS
.count_ones() as u64
+ Self::SCREEN_SPACE_SPECULAR_TRANSMISSION_SHIFT_BITS;
pub fn from_msaa_samples(msaa_samples: u32) -> Self {
let msaa_bits =
(msaa_samples.trailing_zeros() as u64 & Self::MSAA_MASK_BITS) << Self::MSAA_SHIFT_BITS;
Self::from_bits_retain(msaa_bits)
}
/// Create a pipeline key from the view's color target format.
#[inline]
pub fn from_target_format(format: TextureFormat) -> Self {
let code = texture_format_to_code(format)
.expect("Texture format is not supported by the pipeline") as u64;
Self::from_bits_retain(
(code & Self::COLOR_TARGET_FORMAT_MASK_BITS) << Self::COLOR_TARGET_FORMAT_SHIFT_BITS,
)
}
/// Color target format of the main pass for this pipeline key.
#[inline]
pub fn target_format(&self) -> TextureFormat {
let code = ((self.bits() >> Self::COLOR_TARGET_FORMAT_SHIFT_BITS)
& Self::COLOR_TARGET_FORMAT_MASK_BITS) as u8;
texture_format_from_code(code)
.expect("Unknown bits in `COLOR_TARGET_FORMAT_MASK_BITS` of the pipeline key")
}
pub fn msaa_samples(&self) -> u32 {
1 << ((self.bits() >> Self::MSAA_SHIFT_BITS) & Self::MSAA_MASK_BITS)
}
View on GitHub (pinned to 227d3a6c66)
Solutions
- Switch the camera's render target to a supported format: Rgba16Float for HDR, Bgra8UnormSrgb (default swapchain) for LDR
- Keep special-format buffers out of the main camera target: render the scene to a supported intermediate texture, then copy/resolve into the special-format texture in a custom pass
- Before assigning a target format, assert `bevy_render::view::texture_format_to_code(format).is_some()`
Example fix
// before: integer format as the main camera target -> panic in from_target_format image.texture_descriptor.format = TextureFormat::Rgba32Uint; // picking buffer // after: scene renders to a supported format; blit to the picking buffer separately image.texture_descriptor.format = TextureFormat::Rgba16Float; // ... then copy into the Rgba32Uint texture from a dedicated render node
Defensive patterns
Strategy: validation
Validate before calling
use bevy_render::view::texture_format_to_code;
fn assert_camera_format_supported(format: TextureFormat) {
assert!(
texture_format_to_code(format).is_some(),
"format {format:?} is not encodable in MeshPipelineKey; \
use a plain renderable+blendable format (e.g. Rgba16Float)"
);
} Prevention
- Never point Camera::target at integer/data textures; render to a supported intermediate and copy in a custom pass
- Restrict user-configurable target formats to a whitelist checked against texture_format_to_code
- Add a startup system that validates every camera's target format once and panics with a clear message
When it happens
Trigger: Rendering a 3D camera whose color target uses a format outside that list: `TextureFormat::Rgba32Uint`, `Rgba8Uint`, `Rgb10a2Uint`, `Rg16Uint`, `Rgb9e5Ufloat`, 64-bit formats, or block-compressed formats — e.g. `Camera { target: RenderTarget::Texture(handle) }` pointing at an ID/picking buffer. Also triggered by manually calling `MeshPipelineKey::from_target_format` with such a format.
Common situations: Offscreen targets for mouse picking or object-ID passes written directly as the Camera output; data textures reused as render targets; post-processing setups that chose an integer or 64-bit format for precision without checking the mesh pipeline's supported set.
Related errors
- PassSpanGuard::end was never called for {}
- Expected {after:?} to exist
- Expected {before:?} to exist
- Can't create depth attachment. Texture format is not a depth
- Texture format is not supported by the pipeline
AI-assisted analysis of bevyengine/bevy@227d3a6c66 (2026-08-20).
Data as JSON: /api/errors/60db41fe3803440c.
Report an issue: GitHub.