{"record":{"id":"73268ad964b9978f","repo":"bevyengine/bevy","slug":"incompatible-vertex-attribute-types-and","errorCode":null,"errorMessage":"Incompatible vertex attribute types: {} and {}","messagePattern":"Incompatible vertex attribute types: (.+?) and (.+?)","errorType":"exception","errorClass":"MeshMergeError","httpStatus":null,"severity":"error","filePath":"crates/bevy_mesh/src/mesh.rs","lineNumber":3105,"sourceCode":"        }\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,\n            Mesh::ATTRIBUTE_JOINT_INDEX,\n        ];\n        Self {\n            custom_vertex_attributes: BUILTINS\n                .into_iter()\n                .map(|attribute| (attribute.name.into(), attribute))\n                .collect(),","sourceCodeStart":3087,"sourceCodeEnd":3123,"githubUrl":"https://github.com/bevyengine/bevy/blob/8d743eb7dc7fcff57a7d5744d0bbf89620b1b145/crates/bevy_mesh/src/mesh.rs#L3087-L3123","documentation":"MeshMergeError::IncompatibleVertexAttributes (crates/bevy_mesh/src/mesh.rs:3025), returned by Mesh::merge. When both meshes carry an attribute with the same id, merge extends self's buffer with other's; that only works when the VertexAttributeValues variants match exactly (Float32x3 with Float32x3, etc.). A type mismatch is rejected because concatenating different byte layouts would corrupt the buffer.","triggerScenarios":"Calling mesh_a.merge(&mesh_b) where an attribute with the same MeshVertexAttributeId exists in both but with different formats — e.g. ATTRIBUTE_POSITION as Float32x3 in one and Float32x2 in the other, or joint indices as Uint16x4 vs Uint32x4. Checked per attribute during the extend loop (mesh.rs:2182).","commonSituations":"Merging geometry from different sources (a Bevy primitive plus an imported glTF mesh); one side passed through compression/packing (Snorm8x4 normals) while the other kept plain Float32x3; custom attributes registered under the same id with inconsistent formats across code versions.","solutions":["Convert the mismatched attribute in one mesh so both use the same VertexAttributeValues variant, then merge again","Remove the attribute you do not need from one mesh with mesh.remove_attribute(id) before merging","Regenerate one mesh through the same builder/pipeline as the other so attribute formats line up by construction"],"exampleFix":"// before: same attribute id, different formats\nlet mut a = plane_mesh(); // POSITION: Float32x3\nlet mut b = imported_mesh(); // POSITION: Float32x2\na.merge(&b); // Err(IncompatibleVertexAttributes { self_attribute: POSITION(Float32x3), other: Float32x2 })\n\n// after: convert b's positions to Float32x3 first\nlet fixed: Vec<[f32; 3]> = b.attribute(Mesh::ATTRIBUTE_POSITION).unwrap().as_float2().unwrap().iter().map(|p| [p[0], p[1], 0.0]).collect();\nb.insert_attribute(Mesh::ATTRIBUTE_POSITION, fixed);\na.merge(&b).unwrap();","handlingStrategy":"try-catch","validationCode":"use std::mem::discriminant;\nuse bevy_mesh::MeshVertexAttributeId;\n\n// true when every attribute shared by both meshes uses the same values variant\nfn attributes_compatible(a: &Mesh, b: &Mesh) -> bool {\n    a.attributes().all(|(attr, va)| {\n        b.attribute(attr.id).map_or(true, |vb| {\n            discriminant(va) == discriminant(vb)\n        })\n    })\n}","typeGuard":null,"tryCatchPattern":"match a.merge(&b) {\n    Ok(()) => {}\n    Err(MeshMergeError::IncompatibleVertexAttributes { self_attribute, other_attribute }) => {\n        bevy::log::error!(\n            \"cannot merge: {} vs {:?}\", self_attribute.name, other_attribute.map(|a| a.name)\n        );\n        // convert or remove the offending attribute, then retry once\n    }\n    Err(e) => bevy::log::error!(\"merge failed: {e}\"),\n}","preventionTips":["Merged meshes should come from the same builder/pipeline so formats match by construction","Compare VertexAttributeValues discriminants for shared attribute ids before merging","Apply vertex compression only after all merges are done"],"tags":["bevy","mesh","merge","vertex-attribute","format-mismatch"],"backgroundTag":"mesh-merge-incompatible","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"}