{"record":{"id":"e47f1dc7e5d32489","repo":"BabylonJS/Babylon.js","slug":"at-least-one-mesh-is-needed-to-create-the-nav-mesh-e47f1d","errorCode":null,"errorMessage":"At least one mesh is needed to create the nav mesh.","messagePattern":"At least one mesh is needed to create the nav mesh\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/addons/src/navigation/generator/generator.worker.ts","lineNumber":41,"sourceCode":"export function GenerateNavMeshWithWorker(\n    meshes: Array<Mesh>,\n    parameters: INavMeshParametersV2,\n    workerOptions: {\n        /**\n         * Completion callback that is called when the NavMesh generation is complete.\n         * @param navMesh The generated NavMesh.\n         * @param navMeshQuery The NavMeshQuery associated with the generated NavMesh.\n         * @param tileCache Optional TileCache if tile cache generation was used.\n         */\n        completion: (navMesh: NavMesh, navMeshQuery: NavMeshQuery, tileCache?: TileCache) => void;\n        /**\n         *  Worker instance used for asynchronous NavMesh generation.\n         */\n        worker: Worker;\n    }\n) {\n    if (meshes.length === 0) {\n        throw new Error(\"At least one mesh is needed to create the nav mesh.\");\n    }\n\n    // callback function to process the message from the worker\n    workerOptions.worker.onmessage = (e) => {\n        if ((e as any).data?.success === false) {\n            throw new Error(`Unable to generate navMesh: ${e}`);\n        } else {\n            const { navMesh, tileCache } = e.data;\n            if (tileCache) {\n                // if tileCache is present, the binary data contains the navmesh and the tilecache as well\n                const tileCacheArray = new Uint8Array(tileCache);\n                const navMeshData = BuildFromTileCacheData(tileCacheArray, CreateDefaultTileCacheMeshProcess());\n                workerOptions.completion(navMeshData.navMesh, navMeshData.navMeshQuery, navMeshData.tileCache);\n                return;\n            } else {\n                if (navMesh) {\n                    // deserialize the navmesh only (no tilecache present)\n                    const navMeshArray = new Uint8Array(navMesh);","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/addons/src/navigation/generator/generator.worker.ts#L23-L59","documentation":"GenerateNavMeshWithWorker() is the worker-based async path of nav mesh generation (generator.worker.ts:41). Like the single-threaded path, it requires at least one Babylon.js Mesh because the worker needs geometry to rasterize. An empty meshes array is rejected immediately with this error before any worker message is sent.","triggerScenarios":"Calling GenerateNavMeshWithWorker([], parameters, workerOptions) — typically indirectly through CreateNavigationPluginWorkerAsync with an empty mesh array; same root causes as error 10: filtering/tag selection matching nothing, async loads not finished, or conditionally built arrays that end up empty.","commonSituations":"Same as error 10 but in apps using the worker plugin for off-thread generation: game startup calling createNavMesh before level meshes load; tag-based filters returning zero; refactors that pass a subset array that is empty.","solutions":["Pass at least one mesh with geometry: plugin.createNavMesh([ground, ...obstacles], parameters)","Guard the call site: if (meshes.length === 0) { /* fix collection or skip generation */ }","Verify the mesh collection query (tags/predicates/enabled state) actually returns meshes and that async loads completed first"],"exampleFix":"// before\nconst meshes = scene.meshes.filter(m => m.metadata?.nav); // empty\nawait plugin.createNavMeshAsync(meshes, parameters);\n\n// after\nconst meshes = scene.meshes.filter(m => m.metadata?.nav);\nif (meshes.length === 0) {\n    meshes.push(groundMesh); // ensure there is a base nav surface\n}\nawait plugin.createNavMeshAsync(meshes, parameters);","handlingStrategy":"validation","validationCode":"const meshes = scene.meshes.filter(m => m.isEnabled() && m.geometry);\nif (meshes.length === 0) {\n    return; // or push a fallback ground mesh before creating the plugin\n}\nawait CreateNavigationPluginWorkerAsync(meshes, parameters, workerOptions);","typeGuard":"function hasMeshes(meshes: unknown): meshes is Array<Mesh> {\n    return Array.isArray(meshes) && meshes.length > 0;\n}","tryCatchPattern":"try {\n    await plugin.createNavMeshAsync(meshes, parameters);\n} catch (e) {\n    if (e instanceof Error && e.message.includes(\"At least one mesh is needed\")) {\n        // fix mesh collection before retrying\n    }\n}","preventionTips":["Guard worker-based generation behind a meshes.length > 0 check","Collect meshes only after scene.whenReadyAsync() so async loads are complete","Keep a known-good base mesh (e.g. ground) always in the nav mesh list"],"tags":["navigation","recast","navmesh","worker","validation"],"backgroundTag":"empty-mesh-list-navmesh","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}