bevyengine/bevy · critical
FullscreenMaterial::fragment_shader() must not return Shader
Error message
FullscreenMaterial::fragment_shader() must not return ShaderRef::Default
What it means
Bevy's FullscreenMaterial trait (used for fullscreen/post-processing passes) requires every implementation to supply a concrete fragment shader via `fn fragment_shader() -> ShaderRef`. `ShaderRef::Default` means 'no shader specified', so the pipeline builder in `FullscreenMaterial::key`/pipeline creation hits `unimplemented!()` and panics because it cannot construct a RenderPipelineDescriptor without shader source. This is a programmer error in the trait implementation, not a runtime condition.
Source
Thrown at crates/bevy_core_pipeline/src/fullscreen_material.rs:156
render_device: Res<RenderDevice>,
asset_server: Res<AssetServer>,
fullscreen_shader: Res<FullscreenShader>,
) {
let layout = BindGroupLayoutDescriptor::new(
"fullscreen_material_bind_group_layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
texture_2d(TextureSampleType::Float { filterable: true }),
sampler(SamplerBindingType::Filtering),
uniform_buffer::<T>(true),
),
),
);
let sampler = render_device.create_sampler(&SamplerDescriptor::default());
let shader = match T::fragment_shader() {
ShaderRef::Default => {
unimplemented!(
"FullscreenMaterial::fragment_shader() must not return ShaderRef::Default"
)
}
ShaderRef::Handle(handle) => handle,
ShaderRef::Path(path) => asset_server.load(path),
};
let vertex_state = fullscreen_shader.to_vertex_state();
let desc = RenderPipelineDescriptor {
label: Some(format!("fullscreen_material_pipeline<{}>", type_name::<T>()).into()),
layout: vec![layout.clone()],
vertex: vertex_state,
fragment: Some(FragmentState {
shader,
targets: vec![Some(ColorTargetState {
format: TextureFormat::Rgba8UnormSrgb,
blend: None,
write_mask: ColorWrites::ALL,View on GitHub (pinned to 78002f65fa)
Solutions
- Return a concrete shader from the impl: `fn fragment_shader() -> ShaderRef { ShaderRef::Path("shaders/my_post_process.wgsl".into()) }`
- If the shader is already loaded, return `ShaderRef::Handle(handle)` referencing a preloaded `Handle<Shader>`
- Verify the WGSL file exists at the given asset path so the pipeline does not fail on the next lookup
- Add a unit test asserting the impl never returns `ShaderRef::Default` (see exampleFix)
Example fix
// before
impl FullscreenMaterial for MyPostProcessMaterial {
fn fragment_shader() -> ShaderRef {
ShaderRef::Default // panics: unimplemented!()
}
}
// after
impl FullscreenMaterial for MyPostProcessMaterial {
fn fragment_shader() -> ShaderRef {
ShaderRef::Path("shaders/my_post_process.wgsl".into())
}
}
#[test]
fn fragment_shader_is_specified() {
assert!(!matches!(MyPostProcessMaterial::fragment_shader(), ShaderRef::Default));
} Defensive patterns
Strategy: type-guard
Validate before calling
#[test]
fn fullscreen_shader_is_specified() {
use bevy::shader::ShaderRef;
assert!(
!matches!(MyPostProcessMaterial::fragment_shader(), ShaderRef::Default),
"fragment_shader() must return Path or Handle, not Default"
);
} Type guard
fn is_shader_specified(shader_ref: &bevy::shader::ShaderRef) -> bool {
!matches!(shader_ref, bevy::shader::ShaderRef::Default)
} Prevention
- Never leave a ShaderRef-returning method returning Default; stub with a real path during scaffolding
- Run the pipeline once in a dev scene so the panic surfaces immediately, not in production
- Add a unit test asserting the concrete material's fragment_shader() is Path/Handle (associated fn — callable without an instance)
When it happens
Trigger: Implementing a type that derives `AsBindGroup` and implements `FullscreenMaterial` (e.g. a custom post process effect in bevy_core_pipeline) while returning `ShaderRef::Default` from the associated function `fragment_shader()`. The panic fires when the render pipeline is initialized on the render thread.
Common situations: Copying the official post_processing example but deleting the `fragment_shader()` body; refactoring an enum-based shader selection and accidentally falling through to the `Default` variant; upgrading Bevy to a version where FullscreenMaterial moved from bevy_post_process to bevy_core_pipeline and the impl got stubbed out.
Related errors
AI-assisted analysis of bevyengine/bevy@78002f65fa (2026-08-16).
Data as JSON: /api/errors/02c76b6c48c1507f.
Report an issue: GitHub.