bevyengine/bevy · error · MeshMergeDuplicateVerticesError
Mesh access error
Error message
Mesh access error: {0} What it means
MeshMergeDuplicateVerticesError::MeshAccessError (crates/bevy_mesh/src/mesh.rs:3018) wraps the MeshAccessError produced while merge_duplicate_vertices reads vertex data. In this code path the NotFound variant is tolerated (missing indices are expected), so the error that actually surfaces is MeshAccessError::ExtractedToRenderWorld: the mesh's RenderAssetUsages excluded MAIN_WORLD, so its vertex/index data was moved to the render world and is no longer readable from the app world.
Solutions
- Create the mesh with RenderAssetUsages::default() (MAIN_WORLD | RENDER_WORLD) so attributes stay readable
- Do all CPU-side processing (merge_duplicate_vertices, compute_smooth_normals) before spawning/adding the render-world-only mesh
- If the data is already extracted, re-create or re-import the mesh instead of trying to recover it
Example fix
// before: render-world-only mesh let mut mesh = Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::RENDER_WORLD); mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions); // ...after the renderer extracts it: mesh.merge_duplicate_vertices(); // Err(MeshAccessError::ExtractedToRenderWorld) // after: keep data in the main world too let mut mesh = Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default()); mesh.merge_duplicate_vertices().unwrap();
Defensive patterns
Strategy: validation
Validate before calling
fn cpu_accessible(mesh: &Mesh) -> bool {
mesh.asset_usage().contains(RenderAssetUsages::MAIN_WORLD)
}
if cpu_accessible(&mesh) {
mesh.merge_duplicate_vertices()?;
} Try / catch
if let Err(MeshMergeDuplicateVerticesError::MeshAccessError(
MeshAccessError::ExtractedToRenderWorld,
)) = mesh.merge_duplicate_vertices()
{
// re-create the mesh from source data with RenderAssetUsages::default()
} Prevention
- Only use RenderAssetUsages::RENDER_WORLD for meshes you will never touch on the CPU again
- Finish all CPU-side processing (weld, normals, tangents) before adding the mesh to Assets<Mesh>
- Centralize RenderAssetUsages choice in one factory function so projects stay auditable
When it happens
Trigger: Creating a Mesh with RenderAssetUsages::RENDER_WORLD (main-world data dropped after extraction) and then calling merge_duplicate_vertices() on it after the asset has been prepared/extracted once.
Common situations: Memory-optimized asset pipelines that mark runtime-generated meshes as render-world-only; calling mesh post-processing (welding, normals) from a system that runs after rendering has already consumed the asset.
Related errors
- Mesh access error
- Index attribute already set.
- The number of vertices exceeds u32::MAX
- Attribute " " has unexpected format
- Bevy only supports up to
AI-assisted analysis of bevyengine/bevy@8d743eb7dc (2026-08-20).
Data as JSON: /api/errors/f1a4b95744610f31.
Report an issue: GitHub.
Appendix: source
Thrown at crates/bevy_mesh/src/mesh.rs:3098
(
id,
SerializedMeshAttributeData::from_mesh_attribute_data(data),
)
})
.collect(),
indices: mesh.indices.replace(None).expect(MESH_EXTRACTED_ERROR),
}
}
/// Create a [`Mesh`] from a [`SerializedMesh`]. See the documentation for [`SerializedMesh`] for caveats.
///
/// Use [`MeshDeserializer`] if you need to pass extra options to the deserialization process, such as specifying custom vertex attributes.
pub fn into_mesh(self) -> Mesh {
MeshDeserializer::default().deserialize(self)
}
}
/// Use to specify extra options when deserializing a [`SerializedMesh`] into a [`Mesh`].
#[cfg(feature = "serialize")]
pub struct MeshDeserializer {
custom_vertex_attributes: HashMap<Box<str>, MeshVertexAttribute>,
}
#[cfg(feature = "serialize")]
impl Default for MeshDeserializer {
fn default() -> Self {
// Written like this so that the compiler can validate that we use all the built-in attributes.
// If you just added a new attribute and got a compile error, please add it to this list :)
const BUILTINS: [MeshVertexAttribute; Mesh::FIRST_AVAILABLE_CUSTOM_ATTRIBUTE as usize] = [
Mesh::ATTRIBUTE_POSITION,
Mesh::ATTRIBUTE_NORMAL,
Mesh::ATTRIBUTE_UV_0,
Mesh::ATTRIBUTE_UV_1,
Mesh::ATTRIBUTE_TANGENT,
Mesh::ATTRIBUTE_COLOR,
Mesh::ATTRIBUTE_JOINT_WEIGHT,View on GitHub (pinned to 8d743eb7dc)