{"record":{"id":"f1a4b95744610f31","repo":"bevyengine/bevy","slug":"mesh-access-error-0-f1a4b9","errorCode":null,"errorMessage":"Mesh access error: {0}","messagePattern":"Mesh access error: (.+?)","errorType":"exception","errorClass":"MeshMergeDuplicateVerticesError","httpStatus":null,"severity":"error","filePath":"crates/bevy_mesh/src/mesh.rs","lineNumber":3098,"sourceCode":"                    (\n                        id,\n                        SerializedMeshAttributeData::from_mesh_attribute_data(data),\n                    )\n                })\n                .collect(),\n            indices: mesh.indices.replace(None).expect(MESH_EXTRACTED_ERROR),\n        }\n    }\n\n    /// Create a [`Mesh`] from a [`SerializedMesh`]. See the documentation for [`SerializedMesh`] for caveats.\n    ///\n    /// Use [`MeshDeserializer`] if you need to pass extra options to the deserialization process, such as specifying custom vertex attributes.\n    pub fn into_mesh(self) -> Mesh {\n        MeshDeserializer::default().deserialize(self)\n    }\n}\n\n/// Use to specify extra options when deserializing a [`SerializedMesh`] into a [`Mesh`].\n#[cfg(feature = \"serialize\")]\npub struct MeshDeserializer {\n    custom_vertex_attributes: HashMap<Box<str>, MeshVertexAttribute>,\n}\n\n#[cfg(feature = \"serialize\")]\nimpl Default for MeshDeserializer {\n    fn default() -> Self {\n        // Written like this so that the compiler can validate that we use all the built-in attributes.\n        // If you just added a new attribute and got a compile error, please add it to this list :)\n        const BUILTINS: [MeshVertexAttribute; Mesh::FIRST_AVAILABLE_CUSTOM_ATTRIBUTE as usize] = [\n            Mesh::ATTRIBUTE_POSITION,\n            Mesh::ATTRIBUTE_NORMAL,\n            Mesh::ATTRIBUTE_UV_0,\n            Mesh::ATTRIBUTE_UV_1,\n            Mesh::ATTRIBUTE_TANGENT,\n            Mesh::ATTRIBUTE_COLOR,\n            Mesh::ATTRIBUTE_JOINT_WEIGHT,","sourceCodeStart":3080,"sourceCodeEnd":3116,"githubUrl":"https://github.com/bevyengine/bevy/blob/8d743eb7dc7fcff57a7d5744d0bbf89620b1b145/crates/bevy_mesh/src/mesh.rs#L3080-L3116","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: render-world-only mesh\nlet mut mesh = Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::RENDER_WORLD);\nmesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions);\n// ...after the renderer extracts it:\nmesh.merge_duplicate_vertices(); // Err(MeshAccessError::ExtractedToRenderWorld)\n\n// after: keep data in the main world too\nlet mut mesh = Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default());\nmesh.merge_duplicate_vertices().unwrap();","handlingStrategy":"validation","validationCode":"fn cpu_accessible(mesh: &Mesh) -> bool {\n    mesh.asset_usage().contains(RenderAssetUsages::MAIN_WORLD)\n}\n\nif cpu_accessible(&mesh) {\n    mesh.merge_duplicate_vertices()?;\n}","typeGuard":null,"tryCatchPattern":"if let Err(MeshMergeDuplicateVerticesError::MeshAccessError(\n    MeshAccessError::ExtractedToRenderWorld,\n)) = mesh.merge_duplicate_vertices()\n{\n    // re-create the mesh from source data with RenderAssetUsages::default()\n}","preventionTips":["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"],"tags":["bevy","mesh","render-asset-usage","asset-lifetime","merge-duplicate-vertices"],"backgroundTag":"mesh-extracted-to-render-world","analyzedSha":"8d743eb7dc7fcff57a7d5744d0bbf89620b1b145","analyzedAt":"2026-08-20T16:12:39.808Z","contentChangedAt":"2026-08-20T16:12:39.808Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}