bevyengine/bevy · error · MeshWindingInvertError

Indices weren't in chunks according to topology

Error message

Indices weren't in chunks according to topology

What it means

When inverting winding, TriangleList index data is reordered in chunks of 3 and LineList in chunks of 2. If the index buffer length is not an exact multiple of the chunk size, the trailing partial chunk cannot form a complete face, and MeshWindingInvertError::AbruptIndicesEnd is returned instead of corrupting the buffer.

Source

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

            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")]
    PositionsFormat,

    #[error("Face index data references vertices that do not exist")]
    BadIndices,
    #[error("mesh access error: {0}")]
    MeshAccessError(#[from] MeshAccessError),

View on GitHub (pinned to 396ca72708)

Solutions

  1. Validate that the index count divides evenly by 3 (TriangleList) or 2 (LineList) before calling invert_winding
  2. Repair the index buffer so every face is complete: drop or complete the partial chunk
  3. Use slice::as_chunks when building the buffer to detect partial chunks early

Example fix

// before
mesh.invert_winding()?; // Err(AbruptIndicesEnd) when index count % 3 != 0

// after
let index_len = mesh.indices().map(|i| match i {
    Indices::U16(v) => v.len(),
    Indices::U32(v) => v.len(),
});
let chunk = match mesh.primitive_topology() {
    PrimitiveTopology::TriangleList => 3,
    PrimitiveTopology::LineList => 2,
    _ => 1,
};
if index_len.is_some_and(|len| len % chunk == 0) {
    mesh.invert_winding()?;
}
Defensive patterns

Strategy: validation

Validate before calling

fn indices_chunked(mesh: &Mesh) -> bool {
    let Some(indices) = mesh.indices() else { return true; };
    let len = match indices {
        Indices::U16(v) => v.len(),
        Indices::U32(v) => v.len(),
    };
    match mesh.primitive_topology() {
        PrimitiveTopology::TriangleList => len % 3 == 0,
        PrimitiveTopology::LineList => len % 2 == 0,
        _ => true,
    }
}

Try / catch

match mesh.invert_winding() {
    Ok(()) => {}
    Err(MeshWindingInvertError::AbruptIndicesEnd) => { /* repair the index buffer, then retry once */ }
    Err(other) => { /* handle topology/access errors */ }
}

Prevention

When it happens

Trigger: mesh.invert_winding() where the Indices buffer length modulo 3 is nonzero for a TriangleList mesh, or modulo 2 nonzero for a LineList mesh.

Common situations: Hand-built index buffers missing one index; code that pushes or removes single indices while editing a mesh; truncated or partially downloaded imported meshes.

Related errors


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