bevyengine/bevy · error · GenerateTangentsError
the '{0}' vertex attribute should have {1:?} format
Error message
the '{0}' vertex attribute should have {1:?} format What it means
GenerateTangentsError::InvalidVertexAttributeFormat (crates/bevy_mesh/src/mikktspace.rs:71), returned by Mesh::compute_tangents when a required attribute exists but with the wrong VertexFormat. Mikktspace consumes positions and normals as Float32x3 and UVs as Float32x2; anything else (Float32x2 positions, Float32x3 UVs, packed formats) is rejected with the attribute name and the format it found.
Source
Thrown at crates/bevy_mesh/src/mikktspace.rs:71
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(
GenerateTangentsError::MissingVertexAttribute(Mesh::ATTRIBUTE_POSITION.name),
)?;View on GitHub (pinned to 396ca72708)
Solutions
- Read the error payload: '{0}' names the attribute, '{1:?}' the offending format
- Convert and re-insert the attribute with the required format (positions/normals -> Vec<[f32; 3]>, UVs -> Vec<[f32; 2]>)
- Keep compression/packing passes out of the pre-tangent stage; compress after tangents exist
Example fix
// before: UVs stored as float3
mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, vec![[u, v, 0.0f32]; n]);
mesh.compute_tangents(); // Err(InvalidVertexAttributeFormat("Vertex_Uv", Float32x3))
// after: UVs as float2
mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, vec![[u, v]; n]);
mesh.compute_tangents().unwrap(); Defensive patterns
Strategy: validation
Validate before calling
fn tangent_formats_ok(mesh: &Mesh) -> bool {
mesh.attribute(Mesh::ATTRIBUTE_POSITION).is_some_and(|v| v.as_float3().is_some())
&& mesh.attribute(Mesh::ATTRIBUTE_NORMAL).is_some_and(|v| v.as_float3().is_some())
&& mesh.attribute(Mesh::ATTRIBUTE_UV_0).is_some_and(|v| v.as_float2().is_some())
}
if tangent_formats_ok(&mesh) {
mesh.compute_tangents()?;
} Try / catch
if let Err(GenerateTangentsError::InvalidVertexAttributeFormat(name, format)) =
mesh.compute_tangents()
{
bevy::log::error!("'{name}' has format {format:?}; need Float32x3/Float32x3/Float32x2");
} Prevention
- POSITION/NORMAL must be Float32x3 and UV_0 Float32x2 before compute_tangents
- Convert vec3 UVs to vec2 and unpack compressed normals at import time
- Keep vertex compression as a post-tangent step in the pipeline
When it happens
Trigger: Calling compute_tangents() on a mesh where ATTRIBUTE_POSITION/ATTRIBUTE_NORMAL is not Float32x3 or ATTRIBUTE_UV_0 is not Float32x2 — e.g. UVs inserted as [f32; 3] from a texture pipeline, normals carried as Snorm8x4 after compression.
Common situations: Assets imported from engines that use vec3 UVs (w coordinate for projective texturing); vertex-compression passes that repack normals; custom attributes accidentally reusing a standard attribute id with an exotic format.
Related errors
- missing vertex attributes '{0}'
- `Mesh::ATTRIBUTE_POSITION` vertex attributes should be of ty
- Incompatible vertex attribute types: {} and {}
- cannot generate tangents for {0:?}
- missing indices
AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20).
Data as JSON: /api/errors/336e77853ec9181e.
Report an issue: GitHub.