bevyengine/bevy · critical

`OwnedData` has no binding resource

Error message

`OwnedData` has no binding resource

What it means

OwnedBindingResource::get_binding() (bind_group.rs:832) panics on the Data variant because OwnedData does not itself correspond to any binding: it is an unstructured value that must be packed into a buffer by the MaterialBindGroupAllocator before anything can be bound. Calling get_binding() on it bypasses that required packing step.

Source

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

    /// Creates a [`BindingResource`] reference to this
    /// [`OwnedBindingResource`].
    ///
    /// Note that this operation panics if passed a
    /// [`OwnedBindingResource::Data`], because [`OwnedData`] doesn't itself
    /// correspond to any binding and instead requires the
    /// `MaterialBindGroupAllocator` to pack it into a buffer.
    pub fn get_binding(&self) -> BindingResource<'_> {
        match self {
            OwnedBindingResource::Buffer(buffer) => buffer.as_entire_binding(),
            OwnedBindingResource::ShaderBuffer(_) => {
                panic!(
                    "You can't use `get_binding` with a `ShaderBuffer`; fetch the buffer from \
                     the `RenderAssets<GpuShaderBuffer>` instead"
                )
            }
            OwnedBindingResource::TextureView(_, view) => BindingResource::TextureView(view),
            OwnedBindingResource::Sampler(_, sampler) => BindingResource::Sampler(sampler),
            OwnedBindingResource::Data(_) => panic!("`OwnedData` has no binding resource"),
        }
    }
}

impl UnpreparedBindingResource {
    /// Creates a [`BindingResource`] reference to this
    /// [`UnpreparedBindingResource`].
    ///
    /// Note that this operation panics if passed a
    /// [`UnpreparedBindingResource::Data`], because the range doesn't itself
    /// correspond to any binding and instead requires the
    /// `MaterialBindGroupAllocator` to pack it into a buffer.
    pub fn get_binding<'a>(
        &'a self,
        fallback_buffer: &'a FallbackBuffer,
        shader_buffer_assets: &'a RenderAssets<GpuShaderBuffer>,
    ) -> BindingResource<'a> {
        match self {

View on GitHub (pinned to 396ca72708)

Solutions

  1. Let the MaterialBindGroupAllocator pack OwnedData into its slotted buffer and bind at the allocated offset instead of calling get_binding().
  2. If you need a directly bindable resource, store the data in a real wgpu buffer and produce OwnedBindingResource::Buffer rather than Data.
  3. Route custom materials through the standard preparation pipeline.

Example fix

// before
let binding = owned_resource.get_binding(); // panics on Data variant

// after: only bind variants that map to a real binding resource
if matches!(owned_resource, OwnedBindingResource::Data(_)) {
    // let the MaterialBindGroupAllocator pack it into its buffer
} else {
    let binding = owned_resource.get_binding();
}
Defensive patterns

Strategy: type-guard

Type guard

fn is_directly_bindable(res: &OwnedBindingResource) -> bool {
    !matches!(res, OwnedBindingResource::Data(_))
}

Prevention

When it happens

Trigger: Calling get_binding() on OwnedBindingResource::Data - e.g. custom code building a bind group from a material's owned binding resources without going through the MaterialBindGroupAllocator.

Common situations: Hand-rolled bind group construction for materials that use data slots; custom AsBindGroup implementations iterating owned resources; porting code from buffer-based bindings to packed data.

Related errors


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