{"record":{"id":"7f1834c524ff6d9c","repo":"BabylonJS/Babylon.js","slug":"unable-to-get-nav-mesh-no-vertices-or-indices","errorCode":null,"errorMessage":"Unable to get nav mesh. No vertices or indices.","messagePattern":"Unable to get nav mesh\\. No vertices or indices\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/addons/src/navigation/generator/generator.single-thread.ts","lineNumber":32,"sourceCode":" * @param parameters The parameters used to configure the NavMesh generation.\n * @returns An object containing the NavMesh and NavMeshQuery.\n * @remarks This function generates a NavMesh based on the provided meshes and parameters.\n * It supports different configurations such as solo, tiled, and tile cache nav meshes.\n * If you need obstacles, ensure that `maxObstacles` is set to a value greater than 0.\n * Recommended values for `tileSize` are between 32 and 64 when using obstacles/tile cache.\n * If you need a tiled nav mesh, ensure that `tileSize` is set to a value greater than 0.\n * @throws Error if the NavMesh data is invalid or cannot be deserialized.\n */\nexport function GenerateNavMesh(meshes: Array<Mesh>, parameters: INavMeshParametersV2) {\n    const recast = GetRecast();\n\n    if (meshes.length === 0) {\n        throw new Error(\"At least one mesh is needed to create the nav mesh.\");\n    }\n\n    const [positions, indices] = GetPositionsAndIndices(meshes, { doNotReverseIndices: parameters.doNotReverseIndices });\n    if (!positions || !indices) {\n        throw new Error(\"Unable to get nav mesh. No vertices or indices.\");\n    }\n\n    // Decide on the type of nav mesh to generate based on parameters\n    // If tileSize is set, we will generate a tiled nav mesh\n    // If maxObstacles is set, we will generate a tile cache nav mesh\n    // Otherwise, we will generate a solo nav mesh\n    // Note: tileSize is only used for tiled nav meshes, not tile cache nav meshes\n    // If both tileSize and maxObstacles are set, we will generate a tile cache\n    const tileSize = parameters.tileSize ?? 0;\n    const needsTileCache = (parameters.maxObstacles ?? 0) > 0;\n    const needsTiledNavMesh = tileSize > 0;\n    if (needsTileCache) {\n        if (tileSize < 32 || tileSize > 64) {\n            Logger.Warn(\"NavigationPlugin: Tile cache is enabled. Recommended tileSize is 32 to 64. Other values may lead to unexpected behavior.\");\n        }\n    }\n\n    // Create the appropriate configuration based on the parameters","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/addons/src/navigation/generator/generator.single-thread.ts#L14-L50","documentation":"GenerateNavMesh() extracts vertex positions and triangle indices from the supplied meshes via GetPositionsAndIndices() (generator.single-thread.ts:32). If either extraction returns empty/null, there is no usable geometry to feed Recast, so the library throws. Unlike error 10 this means meshes WERE passed, but their geometry could not be read.","triggerScenarios":"Passing meshes with no geometry data: meshes whose geometry has not finished loading/being built, meshes without vertex data (e.g. only transform nodes or empty Mesh instances), meshes with vertices but zero indices, or meshes whose vertex data was disposed; also doNotReverseIndices edge cases where winding extraction yields nothing.","commonSituations":"Calling createNavMesh before loadMesh/async import completes; passing Mesh instances created but never built (no VertexData assigned); meshes whose geometry.dispose() was called (e.g. after cloning with reuse options); procedurally building meshes and generating the nav mesh before the first updateVerticesData/bake; thin instances where base geometry is empty.","solutions":["Ensure meshes are fully loaded/built before generating: await scene.whenReadyAsync() or await the mesh import promise before createNavMesh","Verify each mesh has geometry: check m.geometry && m.getTotalVertices() > 0 && m.getIndices().length > 0","Remove empty/placeholder meshes from the array instead of passing them; pass only meshes with real vertex data","If the mesh is procedurally built, call bakeCurrentTransformIntoVertices / apply vertex data before nav mesh generation"],"exampleFix":"// before\nconst mesh = new Mesh(\"ground\", scene);\nplugin.createNavMesh([mesh], parameters); // no vertex data -> throws\n\n// after\nconst mesh = await CreateGroundAsync(\"ground\", { width: 10, height: 10 }, scene);\nawait scene.whenReadyAsync();\nif (!mesh.geometry || mesh.getTotalVertices() === 0) {\n    throw new Error(\"Ground mesh has no geometry\");\n}\nplugin.createNavMesh([mesh], parameters);","handlingStrategy":"validation","validationCode":"const valid = meshes.filter(m => m.geometry && m.getTotalVertices() > 0 && m.getIndices().length > 0);\nif (valid.length === 0) {\n    throw new Error(\"No meshes with vertex/index data for nav mesh\");\n}\nGenerateNavMesh(valid, parameters);","typeGuard":"function hasGeometry(mesh: Mesh): boolean {\n    return !!mesh.geometry && mesh.getTotalVertices() > 0 && mesh.getIndices().length > 0;\n}","tryCatchPattern":"try {\n    GenerateNavMesh(meshes, parameters);\n} catch (e) {\n    if (e instanceof Error && e.message.includes(\"No vertices or indices\")) {\n        // await scene.whenReadyAsync(); rebuild/proceduralize meshes; retry\n    }\n}","preventionTips":["Call createNavMesh only after all mesh imports/loads resolve (await scene.whenReadyAsync())","Assert each mesh has geometry and >0 vertices/indices before adding it to the list","Avoid passing placeholder/empty Mesh instances or meshes whose geometry was disposed","For procedurally built meshes, apply vertex data before generation"],"tags":["navigation","recast","navmesh","geometry","mesh-data"],"backgroundTag":"navmesh-no-geometry","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}