bevyengine/bevy · error · GenerateTangentsError
missing vertex attributes '{0}'
Error message
missing vertex attributes '{0}' What it means
GenerateTangentsError::MissingVertexAttribute (crates/bevy_mesh/src/mikktspace.rs:69), returned by Mesh::compute_tangents when one of the three required attributes is absent. Tangent generation reads Mesh::ATTRIBUTE_POSITION, Mesh::ATTRIBUTE_NORMAL and Mesh::ATTRIBUTE_UV_0 (mikktspace.rs:88/97/106); the error carries the missing attribute's name so you know exactly which one to add.
Source
Thrown at crates/bevy_mesh/src/mikktspace.rs:69
fn set_tangent(
&mut self,
tangent_space: Option<bevy_mikktspace::TangentSpace>,
face: usize,
vert: usize,
) {
let idx = self.index(face, vert);
self.tangents[idx] = tangent_space.unwrap_or_default().tangent_encoded();
}
}
#[derive(Error, Debug)]
/// Failed to generate tangents for the mesh.
pub enum GenerateTangentsError {
#[error("cannot generate tangents for {0:?}")]
UnsupportedTopology(PrimitiveTopology),
#[error("missing indices")]
MissingIndices,
#[error("missing vertex attributes '{0}'")]
MissingVertexAttribute(&'static str),
#[error("the '{0}' vertex attribute should have {1:?} format")]
InvalidVertexAttributeFormat(&'static str, VertexFormat),
#[error("mesh not suitable for tangent generation")]
MikktspaceError(#[from] bevy_mikktspace::GenerateTangentSpaceError),
#[error("Mesh access error: {0}")]
MeshAccessError(#[from] MeshAccessError),
}
pub(crate) fn generate_tangents_for_mesh(
mesh: &Mesh,
) -> Result<Vec<[f32; 4]>, GenerateTangentsError> {
match mesh.primitive_topology() {
PrimitiveTopology::TriangleList => {}
other => return Err(GenerateTangentsError::UnsupportedTopology(other)),
};
let positions = mesh.try_attribute_option(Mesh::ATTRIBUTE_POSITION)?.ok_or(View on GitHub (pinned to 396ca72708)
Solutions
- Compute normals first: mesh.compute_smooth_normals() (indexed) or duplicate_vertices()+compute_flat_normals()
- Author UVs: mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs) with one Vec2 per vertex
- Inspect the error payload — the '{0}' field names the exact missing attribute
Example fix
// before
mesh.compute_tangents(); // Err(MissingVertexAttribute("Vertex_Normal"))
// after: satisfy all three prerequisites
mesh.compute_smooth_normals().unwrap(); // adds ATTRIBUTE_NORMAL
mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs); // adds UV_0
mesh.compute_tangents().unwrap(); Defensive patterns
Strategy: validation
Validate before calling
fn has_tangent_inputs(mesh: &Mesh) -> bool {
mesh.attribute(Mesh::ATTRIBUTE_POSITION).is_some()
&& mesh.attribute(Mesh::ATTRIBUTE_NORMAL).is_some()
&& mesh.attribute(Mesh::ATTRIBUTE_UV_0).is_some()
}
if has_tangent_inputs(&mesh) {
mesh.compute_tangents()?;
} Type guard
fn tangent_ready(mesh: &Mesh) -> bool {
matches!(mesh.primitive_topology(), PrimitiveTopology::TriangleList)
&& mesh.indices().is_some()
&& mesh.attribute(Mesh::ATTRIBUTE_POSITION).is_some()
&& mesh.attribute(Mesh::ATTRIBUTE_NORMAL).is_some()
&& mesh.attribute(Mesh::ATTRIBUTE_UV_0).is_some()
} Try / catch
if let Err(GenerateTangentsError::MissingVertexAttribute(name)) = mesh.compute_tangents() {
bevy::log::error!("missing '{name}' before compute_tangents");
} Prevention
- compute_tangents needs POSITION + NORMAL + UV_0 — compute normals first
- Author or import a UV set before enabling normal maps
- Use the error payload's attribute name to point at the exact gap
When it happens
Trigger: Calling compute_tangents() on a mesh that has positions and indices but no ATTRIBUTE_NORMAL (normals not yet computed), or no ATTRIBUTE_UV_0 (UVs never authored or stripped by compression).
Common situations: Procedural meshes where the developer forgot normals before adding a normal map; imported assets whose UV set 0 was dropped; pipeline ordering bugs where tangents are computed before compute_smooth_normals has run.
Related errors
- missing indices
- the '{0}' vertex attribute should have {1:?} format
- cannot generate tangents for {0:?}
- mesh not suitable for tangent generation
- failed to generate tangents: {0}
AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20).
Data as JSON: /api/errors/4f0b789420474d39.
Report an issue: GitHub.