bevyengine/bevy · error · ConvertAttributeError
Vertex attribute {0} has format {1:?} but expected {3:?} for
Error message
Vertex attribute {0} has format {1:?} but expected {3:?} for target attribute {2} What it means
ConvertAttributeError::WrongFormat(String semantic, VertexFormat loaded, String attr, VertexFormat expected) is thrown at vertex_attributes.rs:333-345 after conversion: the materialized values' VertexFormat must exactly equal the fixed format of the target MeshVertexAttribute (POSITION must be Float32x3, UV_0 Float32x2, JOINT_INDEX Uint16x4, ...). The classic trigger is an accessor whose format has no conversion path for its semantic — e.g. TEXCOORD_0 as UNnormalized U8x2: into_tex_coord_values (line 241-251) only converts normalized U8x2/U16x2, so values stay Uint8x2 while ATTRIBUTE_UV_0 requires Float32x2.
Source
Thrown at crates/bevy_gltf/src/vertex_attributes.rs:267
s => s.into_any_values(false),
}
}
}
enum ConversionMode {
Any,
Rgba,
JointIndex,
JointWeight,
TexCoord,
}
/// Errors that can occur during the `convert_attribute` function.
#[derive(Error, Debug)]
pub enum ConvertAttributeError {
/// The loaded format ws different than the attribute's intended format.
/// Such as if a `Float32x3` was loaded as a `Float32x2`.
#[error("Vertex attribute {0} has format {1:?} but expected {3:?} for target attribute {2}")]
WrongFormat(String, VertexFormat, String, VertexFormat),
/// Fetching values from the glTF Accessor failed
#[error("{0} in accessor {1}")]
AccessFailed(AccessFailed, usize),
/// A vertex attribute name was not one of the gltf crate's well-known attributes,
/// nor was it registered by a user as a custom attribute. Therefore it is unknown.
#[error("Unknown vertex attribute {0}")]
UnknownName(String),
}
/// map glTF vertex attributes into their `MeshVertexAttribute` forms, optionally
/// converting values if necessary.
pub fn convert_attribute(
semantic: gltf::Semantic,
accessor: gltf::Accessor,
buffer_data: &Vec<Vec<u8>>,
custom_vertex_attributes: &HashMap<Box<str>, MeshVertexAttribute>,
convert_coordinates: bool,View on GitHub (pinned to 396ca72708)
Solutions
- Re-export attributes in the formats Bevy converts for that semantic (float32 positions/uvs; normalized U8/U16 texcoords; unnormalized U8/U16 joints; normalized weights).
- For _CUSTOM_ attributes, register the MeshVertexAttribute with a format matching the accessor data (or convert the data to match the registered format).
- Check the error fields: arg 1 is the semantic, arg 2 what was loaded, arg 4 what was expected — adjust whichever side is wrong.
Example fix
// TEXCOORD_0 accessor (before)
{ "componentType": 5121, "type": "VEC2", "normalized": false }
// (after) normalized bytes convert to Float32x2 as expected
{ "componentType": 5121, "type": "VEC2", "normalized": true } Defensive patterns
Strategy: validation
Validate before calling
use bevy_mesh::VertexFormat;
fn semantic_format_ok(semantic: &gltf::Semantic, loaded: VertexFormat) -> bool {
let expected = match semantic {
gltf::Semantic::Positions => VertexFormat::Float32x3,
gltf::Semantic::Normals => VertexFormat::Float32x3,
gltf::Semantic::Tangents => VertexFormat::Float32x4,
gltf::Semantic::TexCoords(0..=1) => VertexFormat::Float32x2,
gltf::Semantic::Colors(0) => VertexFormat::Float32x4,
gltf::Semantic::Joints(0) => VertexFormat::Uint16x4,
gltf::Semantic::Weights(0) => VertexFormat::Float32x4,
_ => return true,
};
loaded == expected
} Type guard
fn is_wrong_format(err: &ConvertAttributeError) -> Option<(&str, &VertexFormat, &VertexFormat)> {
match err {
ConvertAttributeError::WrongFormat(sem, loaded, _, expected) => Some((sem, loaded, expected)),
_ => None,
}
} Try / catch
match err {
ConvertAttributeError::WrongFormat(sem, loaded, name, expected) => {
error!("{sem} stored as {loaded:?} but {name} needs {expected:?}; re-export the attribute in a convertible format");
}
other => return Err(other.into()),
} Prevention
- Export standard attributes with plain float32 (and normalized int texcoords/joints/weights).
- Register custom _ATTRIBUTES with a MeshVertexAttribute format matching the data.
- Automated import check: assert semantic->expected-format mapping before loading.
When it happens
Trigger: TEXCOORD_0 with "normalized": false byte/short data; JOINTS_0 as normalized U16x4 (loads Unorm16x4, expected Uint16x4); custom vertex attributes registered with a MeshVertexAttribute format that does not match the stored data; POSITION exported as VEC2.
Common situations: Quantized/optimized glTFs (KHR_mesh_quantization derivatives) using unnormalized bytes; teams registering custom attributes with a guessed format; exporters writing unusual joint encodings.
Related errors
- Malformed vertex attribute data
- Unsupported vertex attribute format
- cannot convert VertexAttributeValues::{variant} to {into}
- Source mesh position data is not Float32x3
- Attribute "{0}" has unexpected format {1:?}
AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20).
Data as JSON: /api/errors/4ed5ac30ef7541fc.
Report an issue: GitHub.