{"record":{"id":"02c76b6c48c1507f","repo":"bevyengine/bevy","slug":"fullscreenmaterial-fragment-shader-must-not-ret","errorCode":null,"errorMessage":"FullscreenMaterial::fragment_shader() must not return ShaderRef::Default","messagePattern":"FullscreenMaterial::fragment_shader\\(\\) must not return ShaderRef::Default","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/bevy_core_pipeline/src/fullscreen_material.rs","lineNumber":156,"sourceCode":"    render_device: Res<RenderDevice>,\n    asset_server: Res<AssetServer>,\n    fullscreen_shader: Res<FullscreenShader>,\n) {\n    let layout = BindGroupLayoutDescriptor::new(\n        \"fullscreen_material_bind_group_layout\",\n        &BindGroupLayoutEntries::sequential(\n            ShaderStages::FRAGMENT,\n            (\n                texture_2d(TextureSampleType::Float { filterable: true }),\n                sampler(SamplerBindingType::Filtering),\n                uniform_buffer::<T>(true),\n            ),\n        ),\n    );\n    let sampler = render_device.create_sampler(&SamplerDescriptor::default());\n    let shader = match T::fragment_shader() {\n        ShaderRef::Default => {\n            unimplemented!(\n                \"FullscreenMaterial::fragment_shader() must not return ShaderRef::Default\"\n            )\n        }\n        ShaderRef::Handle(handle) => handle,\n        ShaderRef::Path(path) => asset_server.load(path),\n    };\n\n    let vertex_state = fullscreen_shader.to_vertex_state();\n    let desc = RenderPipelineDescriptor {\n        label: Some(format!(\"fullscreen_material_pipeline<{}>\", type_name::<T>()).into()),\n        layout: vec![layout.clone()],\n        vertex: vertex_state,\n        fragment: Some(FragmentState {\n            shader,\n            targets: vec![Some(ColorTargetState {\n                format: TextureFormat::Rgba8UnormSrgb,\n                blend: None,\n                write_mask: ColorWrites::ALL,","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/bevyengine/bevy/blob/78002f65fa984ededb80915b4a5613f195bc864d/crates/bevy_core_pipeline/src/fullscreen_material.rs#L138-L174","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)"],"exampleFix":"// before\nimpl FullscreenMaterial for MyPostProcessMaterial {\n    fn fragment_shader() -> ShaderRef {\n        ShaderRef::Default // panics: unimplemented!()\n    }\n}\n\n// after\nimpl FullscreenMaterial for MyPostProcessMaterial {\n    fn fragment_shader() -> ShaderRef {\n        ShaderRef::Path(\"shaders/my_post_process.wgsl\".into())\n    }\n}\n\n#[test]\nfn fragment_shader_is_specified() {\n    assert!(!matches!(MyPostProcessMaterial::fragment_shader(), ShaderRef::Default));\n}","handlingStrategy":"type-guard","validationCode":"#[test]\nfn fullscreen_shader_is_specified() {\n    use bevy::shader::ShaderRef;\n    assert!(\n        !matches!(MyPostProcessMaterial::fragment_shader(), ShaderRef::Default),\n        \"fragment_shader() must return Path or Handle, not Default\"\n    );\n}","typeGuard":"fn is_shader_specified(shader_ref: &bevy::shader::ShaderRef) -> bool {\n    !matches!(shader_ref, bevy::shader::ShaderRef::Default)\n}","tryCatchPattern":null,"preventionTips":["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)"],"tags":["bevy","render-pipeline","fullscreen-material","shaders","panic","post-processing"],"backgroundTag":null,"analyzedSha":"78002f65fa984ededb80915b4a5613f195bc864d","analyzedAt":"2026-08-16T09:07:20.800Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}