bevyengine/bevy · critical
The base mesh did not have vertex positions
Error message
The base mesh did not have vertex positions
What it means
Panic thrown while bevy_mesh's Extrusion primitive builds its mesh. After constructing the front and back caps, the extrusion reads the base shape's vertex positions as VertexAttributeValues::Float32x3 to generate the mantel (side walls). If the mesh produced by the base shape builder has no Mesh::ATTRIBUTE_POSITION attribute, or stores it in a non-Float32x3 format, this panic fires. All built-in 2D primitives supply positions, so hitting it almost always means a custom or modified base shape builder that omits them.
Source
Thrown at crates/bevy_mesh/src/primitives/extrusion.rs:243
_ => {
panic!("Meshes used with Extrusions must have a primitive topology of `PrimitiveTopology::TriangleList`");
}
};
}
back_face
};
// An extrusion of depth 0 does not need a mantel
if self.half_depth == 0. {
front_face.merge(&back_face).unwrap();
return front_face;
}
let mantel = {
let Some(VertexAttributeValues::Float32x3(cap_verts)) =
front_face.attribute(Mesh::ATTRIBUTE_POSITION)
else {
panic!("The base mesh did not have vertex positions");
};
debug_assert!(self.segments > 0);
let layers = self.segments + 1;
let layer_depth_delta = self.half_depth * 2.0 / self.segments as f32;
let perimeter = self.base_builder.perimeter();
let (vert_count, index_count) =
perimeter
.iter()
.fold((0, 0), |(verts, indices), perimeter| {
(
verts + layers * perimeter.vertices_per_layer() as usize,
indices + self.segments * perimeter.indices_per_segment(),
)
});
let mut positions = Vec::with_capacity(vert_count);View on GitHub (pinned to 396ca72708)
Solutions
- In the custom base shape's mesh construction, insert positions as Float32x3: mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions) where positions is Vec<[f32; 3]>
- If positions were converted to another format (e.g. half-float or snorm), re-insert them as VertexAttributeValues::Float32x3 before building the Extrusion
- Debug-print the base mesh's attributes to confirm what is missing: build the base shape's mesh alone and inspect mesh.attribute(Mesh::ATTRIBUTE_POSITION)
- While developing the custom shape, substitute a built-in primitive (Rectangle, Circle, RegularPolygon) as the base to verify the rest of the pipeline
Example fix
// before: custom base shape builds a mesh without positions
impl Primitive2d for MyShape { /* ... */ }
fn build_mesh() -> Mesh {
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList, default());
mesh.insert_indices(indices);
// positions never inserted -> panics inside Extrusion
mesh
}
// after: always insert Float32x3 positions
fn build_mesh() -> Mesh {
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList, default());
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions); // Vec<[f32; 3]>
mesh.insert_indices(indices);
mesh
} Defensive patterns
Strategy: validation
Validate before calling
// Validate the base shape's mesh before extruding it (e.g. in a test)
fn base_has_positions(shape: &impl Primitive2d + Extrudable) -> bool {
let mesh = primitives_extrusion_build_base(shape); // whatever builds the cap mesh
matches!(
mesh.attribute(Mesh::ATTRIBUTE_POSITION),
Some(VertexAttributeValues::Float32x3(_))
)
} Type guard
fn has_float32x3_positions(mesh: &Mesh) -> bool {
matches!(
mesh.attribute(Mesh::ATTRIBUTE_POSITION),
Some(VertexAttributeValues::Float32x3(_))
)
} Prevention
- Every custom Primitive2d used as an Extrusion base must insert Mesh::ATTRIBUTE_POSITION as Vec<[f32; 3]> in its mesh builder
- Add a unit test per custom shape asserting the built mesh has Float32x3 positions
- Never convert position attributes to compressed formats before extrusion; compress after, if at all
When it happens
Trigger: Calling .mesh() on an Extrusion (or spawning it as a Mesh) with a non-zero depth, where the base shape's built mesh lacks Mesh::ATTRIBUTE_POSITION or has positions in a format other than Float32x3. A depth of 0 returns early (front face merged with back face) before this check, so only non-zero depths reach the panic.
Common situations: Implementing a custom Primitive2d shape whose mesh construction forgets mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions); converting or compressing positions to another VertexFormat before extruding; test meshes stripped of attributes.
Related errors
- Meshes used with Extrusions must have a primitive topology o
- Failed to insert attribute. Invalid attribute format for {}.
- The number of vertices exceeds u32::MAX
- `Mesh::ATTRIBUTE_POSITION` vertex attributes should be of ty
- The inner and outer meshes should have the same number of ve
AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20).
Data as JSON: /api/errors/b1deeebbaf06cbd9.
Report an issue: GitHub.