bevyengine/bevy · error · MissingVertexAttributeError

Mesh is missing requested attribute: {name} ({id:?}, pipelin

Error message

Mesh is missing requested attribute: {name} ({id:?}, pipeline type: {pipeline_type:?})

What it means

MissingVertexAttributeError is returned by MeshVertexBufferLayout::get_layout (crates/bevy_mesh/src/vertex.rs:146) while assembling the GPU VertexBufferLayout for a pipeline. A pipeline declares the vertex attributes its shader reads (as VertexAttributeDescriptors); if any requested attribute id is not present in the mesh's attribute set, layout building fails with this error, naming the attribute, its id, and the pipeline type when known. It is the standard signal that a shader's vertex input contract and the mesh's data disagree.

Source

Thrown at crates/bevy_mesh/src/vertex.rs:163

            } else {
                return Err(MissingVertexAttributeError {
                    id: attribute_descriptor.id,
                    name: attribute_descriptor.name,
                    pipeline_type: None,
                });
            }
        }

        Ok(VertexBufferLayout {
            array_stride: self.layout.array_stride,
            step_mode: self.layout.step_mode,
            attributes,
        })
    }
}

#[derive(Error, Debug)]
#[error("Mesh is missing requested attribute: {name} ({id:?}, pipeline type: {pipeline_type:?})")]
pub struct MissingVertexAttributeError {
    pub pipeline_type: Option<&'static str>,
    id: MeshVertexAttributeId,
    name: &'static str,
}

pub struct VertexAttributeDescriptor {
    pub shader_location: u32,
    pub id: MeshVertexAttributeId,
    name: &'static str,
}

impl VertexAttributeDescriptor {
    pub const fn new(shader_location: u32, id: MeshVertexAttributeId, name: &'static str) -> Self {
        Self {
            shader_location,
            id,
            name,

View on GitHub (pinned to 396ca72708)

Solutions

  1. Add the missing attribute to the mesh: generate it with mesh.compute_normals() / compute_tangents(), or insert Mesh::ATTRIBUTE_UV_0 with matching vertex count
  2. If the shader does not truly need the attribute, remove it from the pipeline's layout descriptors so get_layout stops requesting it
  3. Select a different shader/pipeline variant for attribute-poor meshes (branch on mesh_vertex_buffer_layout.contains(...))
  4. Read the error's name/id to identify exactly which attribute the pipeline demanded

Example fix

// before: shader pipeline requires UVs the mesh does not have
let layout = mesh.get_vertex_buffer_layout(&[
    Mesh::ATTRIBUTE_POSITION.at_shader_location(0),
    Mesh::ATTRIBUTE_UV_0.at_shader_location(1),
])?; // Err(MissingVertexAttributeError { name: "UV_0" .. })

// after: supply UVs (or drop location 1 from the layout)
let uvs: Vec<[f32; 2]> = (0..vertex_count).map(|_| [0.0, 0.0]).collect();
mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs);
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the mesh provides every attribute the pipeline will request
let layout = mesh.get_mesh_vertex_buffer_layout(); // the mesh's attribute set
let required = [Mesh::ATTRIBUTE_POSITION, Mesh::ATTRIBUTE_NORMAL, Mesh::ATTRIBUTE_UV_0];
let missing: Vec<_> = required.iter().filter(|a| !layout.contains(**a)).collect();
if missing.is_empty() {
    let vbl = layout.get_layout(&[
        Mesh::ATTRIBUTE_POSITION.at_shader_location(0),
        Mesh::ATTRIBUTE_NORMAL.at_shader_location(1),
        Mesh::ATTRIBUTE_UV_0.at_shader_location(2),
    ])?;
}

Type guard

fn mesh_has_attribute(mesh: &Mesh, attribute: MeshVertexAttribute) -> bool {
    mesh.attribute(attribute).is_some()
}

Try / catch

match mesh_layout.get_layout(&descriptors) {
    Ok(vbl) => { /* create pipeline */ }
    Err(e @ MissingVertexAttributeError { name, .. }) => {
        error!("pipeline needs attribute {name} that the mesh lacks: {e}");
        // fall back to a position-only pipeline variant or generate the attribute
    }
}

Prevention

When it happens

Trigger: Specializing or building a render pipeline whose layout requests attributes such as ATTRIBUTE_NORMAL, ATTRIBUTE_UV_0, ATTRIBUTE_TANGENT or ATTRIBUTE_JOINT_INDEX via mesh.get_vertex_buffer_layout()/MeshVertexBufferLayout::get_layout, while the mesh never inserted one of them.

Common situations: A custom Material/shader that samples UVs applied to a mesh generated without UVs; a pipeline that requires NORMALs on a raw TriangleList mesh built from just positions; skinned-shader pipelines run against static meshes; mixing procedurally-built meshes with assets authored in another tool.

Related errors


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