bevyengine/bevy · error

sampler attribute must have matching texture attribute

Error message

sampler attribute must have matching texture attribute

What it means

In `#[derive(AsBindGroup)]` (bevy_render's proc macro) every `#[sampler(n)]` binding must be paired with a matching `#[texture(m)]` attribute, conventionally directly above it on the same field, so the macro can derive the expected texture sample type and the fallback image. During macro expansion the code does `tex_attrs.as_ref().expect("sampler attribute must have matching texture attribute")`, so a sampler without a texture aborts compilation with this panic.

Source

Thrown at crates/bevy_render/macros/src/as_bind_group.rs:711

                    // Add the texture to the `BindlessResourceType` list in the
                    // bindless descriptor.
                    add_bindless_resource_type(
                        &render_path,
                        &mut bindless_resource_types,
                        binding_index,
                        bindless_resource_type,
                    );
                }

                BindingType::Sampler => {
                    let SamplerAttrs {
                        sampler_binding_type,
                        visibility,
                        ..
                    } = get_sampler_attrs(nested_meta_items)?;
                    let TextureAttrs { dimension, .. } = tex_attrs
                        .as_ref()
                        .expect("sampler attribute must have matching texture attribute");

                    let visibility =
                        visibility.hygienic_quote(&quote! { #render_path::render_resource });

                    let fallback_image = get_fallback_image(&render_path, *dimension);

                    let expected_samplers = match sampler_binding_type {
                        SamplerBindingType::Filtering => {
                            quote!( [#render_path::render_resource::TextureSampleType::Float { filterable: true }] )
                        }
                        SamplerBindingType::NonFiltering => quote!([
                            #render_path::render_resource::TextureSampleType::Float { filterable: false },
                            #render_path::render_resource::TextureSampleType::Sint,
                            #render_path::render_resource::TextureSampleType::Uint,
                        ]),
                        SamplerBindingType::Comparison => {
                            quote!( [#render_path::render_resource::TextureSampleType::Depth] )
                        }

View on GitHub (pinned to 396ca72708)

Solutions

  1. Add a matching `#[texture(M, dimension = "2D")]` attribute directly above the `#[sampler(N)]` on the same field
  2. If you truly need no texture, remove the `#[sampler]` attribute and provide the binding manually (custom AsBindGroup impl or a storage binding)
  3. Verify binding indices stay unique per binding type after the fix

Example fix

// before
#[derive(Asset, AsBindGroup)]
struct MyMaterial {
    #[uniform(0)]
    color: Vec4,
    #[sampler(1)]
    tex: Option<Handle<Image>>,
}

// after
#[derive(Asset, AsBindGroup)]
struct MyMaterial {
    #[uniform(0)]
    color: Vec4,
    #[texture(2, dimension = "2D")]
    #[sampler(1)]
    tex: Option<Handle<Image>>,
}
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: A field of an AsBindGroup struct annotated with only `#[sampler(N)]` (no `#[texture(M)]` on the same field), or a texture attribute that was deleted/moved during refactoring while the sampler attribute stayed behind.

Common situations: Writing a new custom material and forgetting the texture attribute; trimming a material down to a sampler-only field; copy-pasting binding attributes between fields and breaking the texture/sampler pairing.

Related errors


AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20). Data as JSON: /api/errors/3303d074b6fad3f8. Report an issue: GitHub.