bevyengine/bevy · error · AsBindGroupError

InvalidSamplerType

InvalidSamplerType

Error message

At binding index {0}, the provided image sampler `{1}` does not match the required sampler type(s) `{2}`.

What it means

AsBindGroupError::InvalidSamplerType(index, provided, required) is reported by as_bind_group when the sampler attached to an image does not match the sampler type(s) the bind group layout requires at that binding index: filtering vs non-filtering vs comparison. The payload names the offending binding index, the sampler actually provided, and the type(s) the shader/layout declared, so you can locate the mismatch precisely.

Source

Thrown at crates/bevy_render/src/render_resource/bind_group.rs:646

        force_no_bindless: bool,
    ) -> Vec<BindGroupLayoutEntry>
    where
        Self: Sized;

    fn bindless_descriptor() -> Option<BindlessDescriptor> {
        None
    }
}

/// An error that occurs during [`AsBindGroup::as_bind_group`] calls.
#[derive(Debug, Error)]
pub enum AsBindGroupError {
    /// The bind group could not be generated. Try again next frame.
    #[error("The bind group could not be generated")]
    RetryNextUpdate,
    #[error("Create the bind group via `as_bind_group()` instead")]
    CreateBindGroupDirectly,
    #[error("At binding index {0}, the provided image sampler `{1}` does not match the required sampler type(s) `{2}`.")]
    InvalidSamplerType(u32, String, String),
}

/// A prepared bind group returned as a result of [`AsBindGroup::as_bind_group`].
pub struct PreparedBindGroup {
    pub bindings: BindingResources,
    pub bind_group: BindGroup,
}

impl PreparedBindGroup {
    pub(crate) fn unprepare(&self) -> BindGroupBuilder {
        let mut data_buffer = vec![];
        BindGroupBuilder {
            binding_resources: UnpreparedBindingResources(
                self.bindings
                    .iter()
                    .map(|(binding, owned_binding_resource)| {
                        let unprepared_binding_resource = match owned_binding_resource {

View on GitHub (pinned to 396ca72708)

Solutions

  1. Make the image's sampler match the shader: for sampler_comparison set image.sampler = TextureSampler::Descriptor(SamplerDescriptor { compare: Some(CompareFunction::LessEqual), ..default() }).
  2. For non-filterable formats, use TextureSampler::NonFiltering and keep the shader declaration consistent.
  3. Use the binding index from the message to find the exact field/attribute to fix; check the derive attributes' sampler types.

Example fix

// before: shader declares a comparison sampler but the image keeps the default filtering one
// @group(2) @binding(0) var shadow_sampler: sampler_comparison;
let image = assets.get(&shadow_texture_handle).unwrap(); // sampler == TextureSampler::Default

// after
let mut image = Image::new(...);
image.sampler = TextureSampler::Descriptor(bevy_render::render_resource::SamplerDescriptor {
    compare: Some(bevy_render::render_resource::CompareFunction::LessEqual),
    ..Default::default()
});
Defensive patterns

Strategy: validation

Validate before calling

// Keep image sampler and shader declaration in sync before building materials:
fn sampler_for_shader(needs_comparison: bool) -> TextureSampler {
    if needs_comparison {
        TextureSampler::Descriptor(SamplerDescriptor {
            compare: Some(CompareFunction::LessEqual),
            ..Default::default()
        })
    } else {
        TextureSampler::Default
    }
}

Try / catch

match material.as_bind_group(&layout, device, queue, &mut param) {
    Err(AsBindGroupError::InvalidSamplerType(index, provided, required)) => {
        error!("binding {index}: sampler {provided} does not satisfy {required}");
        // fix image.sampler or the shader declaration, then retry
    }
    other => other?,
}

Prevention

When it happens

Trigger: Declaring a comparison sampler (sampler_comparison) in WGSL while the image keeps the default filtering TextureSampler; using a non-filterable texture format with a filtering sampler declaration; or specifying the wrong sampler type in #[derive(AsBindGroup)] binding attributes.

Common situations: Shadow-mapping materials that forget to switch the sampled image to a comparison sampler descriptor; integer or depth formats (non-filterable) sampled as if filterable; shader code copied between filtering and non-filtering contexts; upgrading engines where sampler defaults changed.

Related errors


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