{"record":{"id":"b5a3feb968a7751e","repo":"BabylonJS/Babylon.js","slug":"no-valid-mesh-was-provided-for-mesh-or-convex-hull","errorCode":null,"errorMessage":"No valid mesh was provided for mesh or convex hull shape parameter. Please provide a mesh with valid geometry (number of vertices greater than 0).","messagePattern":"No valid mesh was provided for mesh or convex hull shape parameter\\. Please provide a mesh with valid geometry \\(number of vertices greater than 0\\)\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Physics/v2/physicsAggregate.ts","lineNumber":247,"sourceCode":"                    this._options.pointA = this._options.pointA ?? new Vector3(0, min.y + capRadius, 0);\r\n                    this._options.pointB = this._options.pointB ?? new Vector3(0, min.y + extents.y - capRadius, 0);\r\n                }\r\n                break;\r\n            case PhysicsShapeType.CYLINDER:\r\n                {\r\n                    const capRadius = extents.x / 2;\r\n                    this._options.radius = this._options.radius ?? capRadius;\r\n                    this._options.pointA = this._options.pointA ?? new Vector3(0, min.y, 0);\r\n                    this._options.pointB = this._options.pointB ?? new Vector3(0, min.y + extents.y, 0);\r\n                }\r\n                break;\r\n            case PhysicsShapeType.MESH:\r\n            case PhysicsShapeType.CONVEX_HULL:\r\n            case PhysicsShapeType.HEIGHTFIELD:\r\n                if (!this._options.mesh && this._hasVertices(this.transformNode)) {\r\n                    this._options.mesh = this.transformNode as Mesh;\r\n                } else if (!this._options.mesh || !this._hasVertices(this._options.mesh)) {\r\n                    throw new Error(\r\n                        \"No valid mesh was provided for mesh or convex hull shape parameter. Please provide a mesh with valid geometry (number of vertices greater than 0).\"\r\n                    );\r\n                }\r\n                break;\r\n            case PhysicsShapeType.BOX:\r\n                this._options.extents = this._options.extents ?? new Vector3(extents.x, extents.y, extents.z);\r\n                this._options.rotation = this._options.rotation ?? Quaternion.Identity();\r\n                break;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Releases the body, shape and material\r\n     */\r\n    public dispose(): void {\r\n        if (this._nodeDisposeObserver) {\r\n            this.body.transformNode.onDisposeObservable.remove(this._nodeDisposeObserver);\r\n            this._nodeDisposeObserver = null;\r","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Physics/v2/physicsAggregate.ts#L229-L265","documentation":"PhysicsAggregate._addSizeOptions resolves shape sizing inputs from the constructor options. For MESH, CONVEX_HULL, and HEIGHTFIELD types it needs an actual mesh with vertex data: it takes options.mesh if given, otherwise falls back to the transformNode itself when that node has vertices. If neither is usable (no mesh, or mesh with 0 vertices), it throws because the shape would have no geometry to build from.","triggerScenarios":"new PhysicsAggregate(node, PhysicsShapeType.MESH, options, scene) where options.mesh is null and node is a bare TransformNode or an empty Mesh (getTotalVertices() === 0), i.e. the else-if at physicsAggregate.ts:247.","commonSituations":"Attaching a mesh physics shape to a plain TransformNode or camera; creating the aggregate before the mesh's vertices load (async glTF import not awaited); instanced/thin instances where the source mesh has no vertices; passing a GUI or particle object instead of a Mesh.","solutions":["Pass an explicit mesh with geometry: new PhysicsAggregate(node, type, { mesh: sourceMesh, ... }, scene).","Wait for the mesh to finish loading/importing (await ImportMeshAsync / onMeshReady) so vertices exist, then create the aggregate.","Use a sizing-based shape (BOX, SPHERE, CAPSULE) if you only need approximate collision and have no mesh.","Check node.getTotalVertices() > 0 before constructing; also ensure the node is a Mesh, not a bare TransformNode."],"exampleFix":"// before\nconst aggregate = new PhysicsAggregate(emptyNode, PhysicsShapeType.CONVEX_HULL, { mass: 1 }, scene);\n// after\nawait SceneLoader.ImportMeshAsync(\"\", \"assets/\", \"rock.glb\", scene);\nif (rock.getTotalVertices() > 0) {\n  const aggregate = new PhysicsAggregate(rock, PhysicsShapeType.CONVEX_HULL, { mass: 1, mesh: rock }, scene);\n}","handlingStrategy":"validation","validationCode":"if (!(node instanceof Mesh) || node.getTotalVertices() === 0) {\n  throw new Error(\"PhysicsAggregate with MESH/CONVEX_HULL/HEIGHTFIELD requires a Mesh with vertices\");\n}\nconst aggregate = new PhysicsAggregate(node, PhysicsShapeType.CONVEX_HULL, { mass: 1, mesh: node }, scene);","typeGuard":"function hasVertices(n: TransformNode | AbstractMesh): n is Mesh {\n  return n instanceof Mesh && n.getTotalVertices() > 0;\n}","tryCatchPattern":"try {\n  const aggregate = new PhysicsAggregate(node, PhysicsShapeType.CONVEX_HULL, { mass: 1 }, scene);\n} catch (e) {\n  if ((e as Error).message.includes(\"No valid mesh\")) {\n    console.error(\"Provide a loaded Mesh with vertices or use a BOX/SPHERE shape instead\", e);\n  }\n  throw e;\n}","preventionTips":["Create physics aggregates only after mesh assets finish loading (await imports).","Ensure the node is a Mesh with vertices; plain TransformNodes cannot back a mesh shape.","Prefer explicit { mesh: ... } in options over relying on the transformNode fallback.","Use BOX/SPHERE/CAPSULE shapes when you only need approximate collision."],"tags":["physics","mesh","physics-aggregate","validation"],"backgroundTag":"invalid-mesh-geometry","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}