bevyengine/bevy · error · MeshAttributeError

Missing attribute "{0}"

Error message

Missing attribute "{0}"

What it means

MeshAttributeError::MissingAttribute is returned by the expect_attribute_* helpers in bevy_mesh::skinning when a mesh lacks an attribute that was expected with a specific format. It surfaces mainly through SkinnedMeshBounds::from_mesh and InfluenceIterator::new, which require Mesh::ATTRIBUTE_POSITION (Float32x3), Mesh::ATTRIBUTE_JOINT_INDEX (Uint16x4) and Mesh::ATTRIBUTE_JOINT_WEIGHT (Float32x4). The message names the missing attribute.

Source

Thrown at crates/bevy_mesh/src/skinning.rs:414

            self.influence_index += 1;

            if joint_weight > 0.0 {
                return Some(Influence {
                    vertex_index: self.vertex_index,
                    joint_index: JointIndex(joint_index),
                    joint_weight,
                });
            }
        }
    }
}

/// Generic error for when a mesh was expected to have a certain attribute with
/// a certain format.
#[derive(Copy, Clone, PartialEq, Debug, Error)]
pub enum MeshAttributeError {
    #[error("Missing attribute \"{0}\"")]
    MissingAttribute(&'static str),
    #[error("Attribute \"{0}\" has unexpected format {1:?}")]
    UnexpectedFormat(&'static str, VertexFormat),
}

// Implements a function that returns a mesh attribute's data or `MeshAttributeError`.
//
// ```
// impl_expect_attribute!(expect_attribute_float32x3, Float32x3, [f32; 3]);
//
// let positions: Vec<[f32; 3]> = expect_attribute_float32x3(mesh, Mesh::ATTRIBUTE_POSITION)?;
// ```
macro_rules! impl_expect_attribute {
    ($name:ident, $value_type:ident, $output_type:ty) => {
        fn $name<'a>(
            mesh: &'a Mesh,
            attribute: MeshVertexAttribute,
        ) -> Result<&'a Vec<$output_type>, MeshAttributeError> {

View on GitHub (pinned to 396ca72708)

Solutions

  1. Insert the missing skin attributes in the exact expected formats: JOINT_INDEX as VertexAttributeValues::Uint16x4 and JOINT_WEIGHT as VertexAttributeValues::Float32x4 (plus POSITION as Float32x3)
  2. Guard the call: only derive SkinnedMeshBounds for meshes that actually carry skin attributes (check mesh.attribute(Mesh::ATTRIBUTE_JOINT_INDEX).is_some())
  3. If the mesh is supposed to be static, skip from_mesh entirely and use mesh.compute_aabb()
  4. Inspect the error's attribute name to see exactly which of the three attributes is absent

Example fix

// before: mesh without skin data
let bounds = SkinnedMeshBounds::from_mesh(&mesh)?; // Err(MissingAttribute("JOINT_INDEX"))

// after: provide the required attributes
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions);        // Vec<[f32; 3]>
mesh.insert_attribute(Mesh::ATTRIBUTE_JOINT_INDEX, joint_indices); // Vec<[u16; 4]>
mesh.insert_attribute(Mesh::ATTRIBUTE_JOINT_WEIGHT, weights);     // Vec<[f32; 4]>
let bounds = SkinnedMeshBounds::from_mesh(&mesh)?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_skinned_mesh_ready(mesh: &Mesh) -> bool {
    mesh.attribute(Mesh::ATTRIBUTE_POSITION).is_some()
        && mesh.attribute(Mesh::ATTRIBUTE_JOINT_INDEX).is_some()
        && mesh.attribute(Mesh::ATTRIBUTE_JOINT_WEIGHT).is_some()
}

if is_skinned_mesh_ready(&mesh) {
    let bounds = SkinnedMeshBounds::from_mesh(&mesh)?;
}

Type guard

fn has_skin_attributes(mesh: &Mesh) -> bool {
    matches!(mesh.attribute(Mesh::ATTRIBUTE_JOINT_INDEX), Some(VertexAttributeValues::Uint16x4(_)))
        && matches!(mesh.attribute(Mesh::ATTRIBUTE_JOINT_WEIGHT), Some(VertexAttributeValues::Float32x4(_)))
}

Try / catch

match SkinnedMeshBounds::from_mesh(&mesh) {
    Ok(bounds) => { /* use */ }
    Err(SkinnedMeshBoundsError::MeshAttributeError(
        MeshAttributeError::MissingAttribute(name),
    )) => {
        warn!("skipping bounds for mesh without attribute {name}");
    }
    Err(other) => warn!("skinning bounds failed: {other:?}"),
}

Prevention

When it happens

Trigger: Calling SkinnedMeshBounds::from_mesh on a mesh that has no JOINT_INDEX or JOINT_WEIGHT attribute (e.g. a static mesh), or whose POSITION attribute was never inserted; also any direct use of InfluenceIterator::new on such a mesh.

Common situations: Running skinning/bounds systems on meshes imported without skin data; custom meshes built from scratch where skin attributes were forgotten; blending code that copies positions but drops joint attributes; assuming all meshes in a scene are skinned.

Related errors


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