BabylonJS/Babylon.js · error

Unable to build a mesh. Manifold has 0 vertex

Error message

Unable to build a mesh. Manifold has 0 vertex

What it means

toMesh rebuilds a Babylon Mesh from the CSG2's vertex data; if the resulting Manifold contains zero vertices (e.g. an empty result geometry), it throws because a mesh cannot be built from empty vertex data. This guards against producing degenerate, invisible meshes from a CSG operation.

Source

Thrown at packages/dev/core/src/Meshes/csg2.ts:233

     * @returns a new Mesh
     */
    public toMesh(name: string, scene?: Scene, options?: Partial<IMeshRebuildOptions>): Mesh {
        const localOptions = {
            rebuildNormals: false,
            centerMesh: true,
            ...options,
        };
        const vertexData = this.toVertexData({ rebuildNormals: localOptions.rebuildNormals });
        const normalComponent = this._vertexStructure.find((c) => c.kind === VertexBuffer.NormalKind);
        const manifoldMesh: IManifoldMesh = this._manifold.getMesh(localOptions.rebuildNormals && normalComponent ? [3, 4, 5] : undefined);
        const vertexCount = manifoldMesh.vertProperties.length / manifoldMesh.numProp;

        // Rebuild mesh from vertex data
        const output = new Mesh(name, scene);
        vertexData.applyToMesh(output);

        if (!vertexCount) {
            throw new Error("Unable to build a mesh. Manifold has 0 vertex");
        }

        // Center mesh
        if (localOptions.centerMesh) {
            const extents = output.getBoundingInfo().boundingSphere.center;
            output.position.set(-extents.x, -extents.y, -extents.z);
            output.bakeCurrentTransformIntoVertices();
        }

        // Submeshes
        let id = manifoldMesh.runOriginalID[0];
        let start = manifoldMesh.runIndex[0];
        let materialIndex = 0;
        const materials: Material[] = [];
        scene = output.getScene();
        for (let run = 0; run < manifoldMesh.numRun; ++run) {
            const nextID = manifoldMesh.runOriginalID[run + 1];
            if (nextID !== id) {

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Verify the operands actually overlap before the boolean operation
  2. Check the CSG result (vertex/vertexCount) for emptiness and fall back to the original mesh
  3. Fix the source mesh so it contains geometry (non-zero vertex count) before converting

Example fix

// before
const result = a.subtract(b).toMesh('diff', scene); // may be empty
// after
const c = a.subtract(b);
if (c.getCVertices?.() ?? true) { /* check non-empty */ }
const result = c.toMesh('diff', scene);
Defensive patterns

Strategy: validation

Validate before calling

const result = a.intersect(b);
// guard against empty boolean result before toMesh
if (!result) throw new Error('CSG result is empty');

Type guard

const nonEmpty = (c: CSG2): boolean => { try { return !!c; } catch { return false; } };

Try / catch

try {
  mesh = result.toMesh(name, scene);
} catch (e) {
  if (String(e).includes('0 vertex')) { mesh = fallbackOriginalMesh(); }
  else throw e;
}

Prevention

When it happens

Trigger: Calling csg.toMesh() after an operation whose result was empty — subtracting a mesh that fully contains the other, intersecting disjoint solids, or building the CSG from an empty/invalid mesh.

Common situations: Boolean ops between non-overlapping objects; a subtract where the tool body completely swallows the target; importing meshes that failed to produce geometry.

Related errors


AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30). Data as JSON: /api/errors/06a9ac8cfe04f0e3. Report an issue: GitHub.