{"record":{"id":"56f98019016600d8","repo":"bevyengine/bevy","slug":"incompatible-primitive-topologies-and","errorCode":null,"errorMessage":"Incompatible primitive topologies: {:?} and {:?}","messagePattern":"Incompatible primitive topologies: (.+?) and (.+?)","errorType":"exception","errorClass":"MeshMergeError","httpStatus":null,"severity":"error","filePath":"crates/bevy_mesh/src/mesh.rs","lineNumber":3030,"sourceCode":"\n/// Error that can occur when calling [`Mesh::merge_duplicate_vertices`]\n#[derive(Error, Debug, Clone)]\npub enum MeshMergeDuplicateVerticesError {\n    #[error(\"Index attribute already set.\")]\n    IndicesAlreadySet,\n    #[error(\"Mesh access error: {0}\")]\n    MeshAccessError(#[from] MeshAccessError),\n}\n\n/// Error that can occur when calling [`Mesh::merge`].\n#[derive(Error, Debug, Clone)]\npub enum MeshMergeError {\n    #[error(\"Incompatible vertex attribute types: {} and {}\", self_attribute.name, other_attribute.map(|a| a.name).unwrap_or(\"None\"))]\n    IncompatibleVertexAttributes {\n        self_attribute: MeshVertexAttribute,\n        other_attribute: Option<MeshVertexAttribute>,\n    },\n    #[error(\n        \"Incompatible primitive topologies: {:?} and {:?}\",\n        self_primitive_topology,\n        other_primitive_topology\n    )]\n    IncompatiblePrimitiveTopology {\n        self_primitive_topology: PrimitiveTopology,\n        other_primitive_topology: PrimitiveTopology,\n    },\n    #[error(\"Mesh access error: {0}\")]\n    MeshAccessError(#[from] MeshAccessError),\n}\n\n#[cfg(test)]\nmod tests {\n    use super::Mesh;\n    #[cfg(feature = \"serialize\")]\n    use super::SerializedMesh;\n    use crate::mesh::{Indices, MeshWindingInvertError, VertexAttributeValues};","sourceCodeStart":3012,"sourceCodeEnd":3048,"githubUrl":"https://github.com/bevyengine/bevy/blob/396ca727080776bd313bb892423b7d94e03b81b4/crates/bevy_mesh/src/mesh.rs#L3012-L3048","documentation":"MeshMergeError::IncompatiblePrimitiveTopology (crates/bevy_mesh/src/mesh.rs:3030), returned by Mesh::merge as its very first check (mesh.rs:2135). Merging concatenates index buffers with an offset, which is only meaningful when both meshes interpret those indices under the same primitive topology; mixing e.g. TriangleList with TriangleStrip would produce garbage geometry, so it is rejected up front.","triggerScenarios":"Calling mesh_a.merge(&mesh_b) where mesh_a was created with PrimitiveTopology::TriangleList and mesh_b with PrimitiveTopology::TriangleStrip (or any other differing variant such as LineList vs LineStrip).","commonSituations":"Merging a Bevy primitive (always TriangleList) with a custom mesh built as TriangleStrip to save indices; mixing 2D line geometry (LineList) with triangle meshes in a batching pass; topology defaults changing between asset importer versions.","solutions":["Rebuild one mesh with the same PrimitiveTopology you pass to Mesh::new for the other","Convert the strip mesh's triangle list (re-expand strip indices into triangles) before merging","Batch by topology: group meshes into merge sets that share a topology instead of merging across groups"],"exampleFix":"// before\nlet mut a = Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default());\nlet b = Mesh::new(PrimitiveTopology::TriangleStrip, RenderAssetUsages::default());\na.merge(&b); // Err(IncompatiblePrimitiveTopology { self: TriangleList, other: TriangleStrip })\n\n// after: build both with the same topology\nlet b = Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default());\na.merge(&b).unwrap();","handlingStrategy":"validation","validationCode":"fn same_topology(a: &Mesh, b: &Mesh) -> bool {\n    a.primitive_topology() == b.primitive_topology()\n}\n\nif same_topology(&mesh_a, &mesh_b) {\n    mesh_a.merge(&mesh_b)?;\n}","typeGuard":"fn mergeable_pair<'a>(a: &'a mut Mesh, b: &'a Mesh) -> Option<&'a mut Mesh> {\n    (a.primitive_topology() == b.primitive_topology()).then_some(a)\n}","tryCatchPattern":"if let Err(MeshMergeError::IncompatiblePrimitiveTopology {\n    self_primitive_topology,\n    other_primitive_topology,\n}) = mesh_a.merge(&mesh_b)\n{\n    bevy::log::error!(\"topology mismatch: {self_primitive_topology:?} vs {other_primitive_topology:?}\");\n}","preventionTips":["Set topology once in a shared factory for all meshes that will be batched together","Group merge candidates by PrimitiveTopology before merging","Beware TriangleStrip leftovers when porting older mesh code"],"tags":["bevy","mesh","merge","primitive-topology","mismatch"],"backgroundTag":"primitive-topology-mismatch","analyzedSha":"396ca727080776bd313bb892423b7d94e03b81b4","analyzedAt":"2026-08-20T16:12:39.808Z","contentChangedAt":"2026-08-20T16:12:39.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}