bevyengine/bevy · critical
The number of vertices exceeds u32::MAX
Error message
The number of vertices exceeds u32::MAX
What it means
Raised by Mesh::merge_duplicate_vertices (crates/bevy_mesh/src/mesh.rs:1512) when the map of deduplicated vertices grows past u32::MAX (4,294,967,295) unique vertices. Bevy mesh index buffers store indices as u32, so the operation aborts with an expect panic instead of silently overflowing indices. In practice this guard is almost unreachable because storing that many vertices requires an enormous amount of RAM.
Source
Thrown at crates/bevy_mesh/src/mesh.rs:1512
.iter()
.map(|(k, v)| {
(
*k,
MeshAttributeData {
attribute: v.attribute,
values: VertexAttributeValues::new(VertexFormat::from(&v.values)),
},
)
})
.collect();
let mut vertex_to_new_index: HashMap<VertexRef, u32> = HashMap::new();
let mut indices = Vec::with_capacity(self.count_vertices());
for i in 0..self.count_vertices() {
let len: u32 = vertex_to_new_index
.len()
.try_into()
.expect("The number of vertices exceeds u32::MAX");
let vertex_ref = VertexRef {
mesh_attributes: old_attributes,
i,
};
let j = match vertex_to_new_index.entry(vertex_ref) {
hash_map::Entry::Occupied(e) => *e.get(),
hash_map::Entry::Vacant(e) => {
e.insert(len);
vertex_ref.push_to(&mut new_attributes);
len
}
};
indices.push(j);
}
drop(vertex_to_new_index);
for v in new_attributes.values_mut() {
v.values.shrink_to_fit();View on GitHub (pinned to 396ca72708)
Solutions
- Split the geometry into several Meshes so each stays far below u32::MAX vertices, and deduplicate per mesh
- Deduplicate vertices while building each chunk instead of after merging everything
- Audit mesh.count_vertices() growth in your asset pipeline and cap or split when it approaches the limit
Example fix
// before: one giant mesh, panics when unique vertices exceed u32::MAX
let mut mesh = build_huge_procedural_mesh();
mesh.merge_duplicate_vertices(); // expect("The number of vertices exceeds u32::MAX")
// after: keep each chunk small and dedupe per chunk
for mut chunk in build_huge_procedural_mesh().split_into_chunks(10_000_000) {
chunk.merge_duplicate_vertices()?;
commands.spawn(Mesh3d(meshes.add(chunk)));
} Defensive patterns
Strategy: validation
Validate before calling
// merge_duplicate_vertices can address at most u32::MAX unique vertices
fn can_dedupe(mesh: &Mesh) -> bool {
mesh.count_vertices() <= u32::MAX as usize // unique count is always <= total
}
if can_dedupe(&mesh) {
mesh.merge_duplicate_vertices()?;
} else {
// split the mesh first
} Prevention
- Track count_vertices() in your asset pipeline and split meshes long before they approach 4 billion vertices
- Deduplicate per chunk while generating, not after concatenating everything
- Treat any mesh measured in hundreds of millions of vertices as a design smell for a single draw call
When it happens
Trigger: Calling mesh.merge_duplicate_vertices() on a Mesh whose unique-vertex count (vertices identical across all attributes are merged into one) exceeds 2^32 - 1. Typically only possible by concatenating gigantic procedural datasets (terrain voxels, point clouds) into a single Mesh and then deduplicating.
Common situations: Chunked terrain or voxel engines that merge thousands of chunks into one Mesh; research/HLOD pipelines that accumulate geometry over long sessions; loading a pathological asset that expanded vertices via duplicate_vertices before deduplication.
Related errors
- Failed to insert attribute. Invalid attribute format for {}.
- `Mesh::ATTRIBUTE_POSITION` vertex attributes should be of ty
- Index attribute already set.
- Mesh access error: {0}
- Too many vertex components in morph target, max is {MAX_COMP
AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20).
Data as JSON: /api/errors/0b7bd2e3c38acc8a.
Report an issue: GitHub.