bevyengine/bevy · error · MeshWindingInvertError

Mesh winding inversion does not work for primitive topology

Error message

Mesh winding inversion does not work for primitive topology `PointList`

What it means

Mesh::invert_winding() (crates/bevy_mesh/src/mesh.rs:1560) swaps vertices inside each face to flip triangle or line orientation. PointList meshes have no faces or edges to reorder, so the operation is rejected up front with MeshWindingInvertError::WrongTopology.

Source

Thrown at crates/bevy_mesh/src/index.rs:53

            FourIterators::Fourth(iter) => iter.next(),
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        match self {
            FourIterators::First(iter) => iter.size_hint(),
            FourIterators::Second(iter) => iter.size_hint(),
            FourIterators::Third(iter) => iter.size_hint(),
            FourIterators::Fourth(iter) => iter.size_hint(),
        }
    }
}

/// An error that occurred while trying to invert the winding of a [`Mesh`](super::Mesh).
#[derive(Debug, Error)]
pub enum MeshWindingInvertError {
    /// This error occurs when you try to invert the winding for a mesh with [`PrimitiveTopology::PointList`](super::PrimitiveTopology::PointList).
    #[error("Mesh winding inversion does not work for primitive topology `PointList`")]
    WrongTopology,

    /// This error occurs when you try to invert the winding for a mesh with
    /// * [`PrimitiveTopology::TriangleList`](super::PrimitiveTopology::TriangleList), but the indices are not in chunks of 3.
    /// * [`PrimitiveTopology::LineList`](super::PrimitiveTopology::LineList), but the indices are not in chunks of 2.
    #[error("Indices weren't in chunks according to topology")]
    AbruptIndicesEnd,
    #[error("Mesh access error: {0}")]
    MeshAccessError(#[from] MeshAccessError),
}

/// An error that occurred while trying to extract a collection of triangles from a [`Mesh`](super::Mesh).
#[derive(Debug, Error)]
pub enum MeshTrianglesError {
    #[error("Source mesh does not have primitive topology TriangleList or TriangleStrip")]
    WrongTopology,

    #[error("Source mesh position data is not Float32x3")]

View on GitHub (pinned to 396ca72708)

Solutions

  1. Skip inversion for PointList meshes: they have no winding to flip
  2. Gate on topology and only call invert_winding for TriangleList, TriangleStrip, LineList and LineStrip
  3. If triangles were expected, fix the mesh construction that set PointList topology

Example fix

// before
mesh.invert_winding()?; // Err(WrongTopology) on point lists

// after
if !matches!(mesh.primitive_topology(), PrimitiveTopology::PointList) {
    mesh.invert_winding()?;
}
Defensive patterns

Strategy: validation

Validate before calling

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

if can_invert_winding(&mesh) {
    mesh.invert_winding()?;
}

Try / catch

if let Err(MeshWindingInvertError::WrongTopology) = mesh.invert_winding() {
    // point list: nothing to invert, continue
}

Prevention

When it happens

Trigger: mesh.invert_winding() on a mesh whose primitive_topology() is PrimitiveTopology::PointList (particles, point clouds, meshes built for gl_Point rendering).

Common situations: Generic flip-normals utilities applied to every mesh in an Assets<Mesh> collection; point-cloud assets routed through the same pipeline as triangle meshes; mesh-import code that defaults to PointList for unknown formats.

Related errors


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