bevyengine/bevy · error · GenerateTangentsError

cannot generate tangents for {0:?}

Error message

cannot generate tangents for {0:?}

What it means

GenerateTangentsError::UnsupportedTopology (crates/bevy_mesh/src/mikktspace.rs:65), returned by Mesh::compute_tangents / generate_tangents_for_mesh. The mikktspace tangent-generation algorithm walks triangles by index triplets, so the mesh must use PrimitiveTopology::TriangleList; any other topology is rejected with the offending variant embedded in the error.

Source

Thrown at crates/bevy_mesh/src/mikktspace.rs:65

    fn tex_coord(&self, face: usize, vert: usize) -> [f32; 2] {
        self.uvs[self.index(face, vert)]
    }

    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 => {}

View on GitHub (pinned to 396ca72708)

Solutions

  1. Build the mesh with PrimitiveTopology::TriangleList before compute_tangents()
  2. Convert strip indices to triangle-list indices (expand each consecutive triple) and re-insert via insert_indices
  3. Skip tangent generation for non-triangle meshes (tangents are meaningless for lines/points)

Example fix

// before
let mut mesh = Mesh::new(PrimitiveTopology::TriangleStrip, RenderAssetUsages::default());
// ...positions, normals, uvs, indices...
mesh.compute_tangents(); // Err(UnsupportedTopology(TriangleStrip))

// after
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default());
// ...same attributes...
mesh.compute_tangents().unwrap();
Defensive patterns

Strategy: validation

Validate before calling

if mesh.primitive_topology() == PrimitiveTopology::TriangleList {
    mesh.compute_tangents()?;
} else {
    // convert to triangle list or skip tangents
}

Type guard

fn is_triangle_list(mesh: &Mesh) -> bool {
    matches!(mesh.primitive_topology(), PrimitiveTopology::TriangleList)
}

Try / catch

if let Err(GenerateTangentsError::UnsupportedTopology(topo)) = mesh.compute_tangents() {
    bevy::log::error!("compute_tangents needs TriangleList, got {topo:?}");
}

Prevention

When it happens

Trigger: Calling mesh.compute_tangents() on a mesh created with PrimitiveTopology::TriangleStrip, PointList, LineList or LineStrip. The match at mikktspace.rs:83 sends every non-TriangleList topology into this error before any attribute is read.

Common situations: Normal-mapping a strip-optimized custom mesh to save index memory; accidentally reusing a 2D/line mesh constructor for a 3D shaded asset; importers that emit strips for legacy data.

Related errors


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