bevyengine/bevy · error · MeshWindingInvertError

Mesh access error: {0}

Error message

Mesh access error: {0}

What it means

invert_winding() must mutate vertex and index data on the CPU. MeshWindingInvertError::MeshAccessError wraps a MeshAccessError raised by the mesh's extractable-data accessors: the vertex/index data was already moved to the RenderWorld because the mesh's asset_usage excludes MAIN_WORLD, so there is nothing on the CPU side to reorder.

Source

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

            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. Include MAIN_WORLD in asset_usage: mesh.asset_usage = RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD
  2. Perform winding edits before the mesh is added as a render asset
  3. Keep a CPU-side clone of the mesh data and invert the clone

Example fix

// before
mesh.asset_usage = RenderAssetUsages::RENDER_WORLD;
// ... after extraction:
mesh.invert_winding()?; // Err(MeshAccessError::ExtractedToRenderWorld)

// after
mesh.asset_usage = RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD;
mesh.invert_winding()?; // data still available on the CPU
Defensive patterns

Strategy: validation

Validate before calling

fn mesh_editable_on_cpu(mesh: &Mesh) -> bool {
    mesh.asset_usage.contains(RenderAssetUsages::MAIN_WORLD)
}

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

Try / catch

match mesh.invert_winding() {
    Ok(()) => {}
    Err(MeshWindingInvertError::MeshAccessError(
        MeshAccessError::ExtractedToRenderWorld,
    )) => { /* re-insert data or edit a CPU-side clone instead */ }
    Err(other) => { /* topology / index errors */ }
}

Prevention

When it happens

Trigger: Calling mesh.invert_winding() after the mesh was rendered with asset_usage set to only RenderAssetUsages::RENDER_WORLD; the extraction step has already consumed the CPU-side data.

Common situations: Memory-saving asset_usage set to RENDER_WORLD, then a later system tries to flip winding for a mirror effect or double-sided hack; editing meshes in systems that run after the render schedule.

Related errors


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