BabylonJS/Babylon.js · error · Error
At least one mesh is needed to create the nav mesh.
Error message
At least one mesh is needed to create the nav mesh.
What it means
GenerateNavMesh() is the synchronous nav mesh builder in the Babylon.js navigation addon (generator.single-thread.ts:27). Before doing any work it validates that the caller supplied at least one Babylon.js Mesh, because the nav mesh is generated from the geometry of the meshes passed in. An empty meshes array means there is no geometry to rasterize into a Recast nav mesh, so the function throws immediately rather than returning an empty or invalid nav mesh.
Source
Thrown at packages/dev/addons/src/navigation/generator/generator.single-thread.ts:27
import { GetRecast } from "../factory/common";
/**
* Builds a NavMesh and NavMeshQuery from meshes using provided parameters.
* @param meshes The array of meshes used to create the NavMesh.
* @param parameters The parameters used to configure the NavMesh generation.
* @returns An object containing the NavMesh and NavMeshQuery.
* @remarks This function generates a NavMesh based on the provided meshes and parameters.
* It supports different configurations such as solo, tiled, and tile cache nav meshes.
* If you need obstacles, ensure that `maxObstacles` is set to a value greater than 0.
* Recommended values for `tileSize` are between 32 and 64 when using obstacles/tile cache.
* If you need a tiled nav mesh, ensure that `tileSize` is set to a value greater than 0.
* @throws Error if the NavMesh data is invalid or cannot be deserialized.
*/
export function GenerateNavMesh(meshes: Array<Mesh>, parameters: INavMeshParametersV2) {
const recast = GetRecast();
if (meshes.length === 0) {
throw new Error("At least one mesh is needed to create the nav mesh.");
}
const [positions, indices] = GetPositionsAndIndices(meshes, { doNotReverseIndices: parameters.doNotReverseIndices });
if (!positions || !indices) {
throw new Error("Unable to get nav mesh. No vertices or indices.");
}
// Decide on the type of nav mesh to generate based on parameters
// If tileSize is set, we will generate a tiled nav mesh
// If maxObstacles is set, we will generate a tile cache nav mesh
// Otherwise, we will generate a solo nav mesh
// Note: tileSize is only used for tiled nav meshes, not tile cache nav meshes
// If both tileSize and maxObstacles are set, we will generate a tile cache
const tileSize = parameters.tileSize ?? 0;
const needsTileCache = (parameters.maxObstacles ?? 0) > 0;
const needsTiledNavMesh = tileSize > 0;
if (needsTileCache) {
if (tileSize < 32 || tileSize > 64) {View on GitHub (pinned to 0592b347b8)
Solutions
- Pass at least one mesh with geometry: const plugin = await CreateNavigationPluginAsync(); plugin.createNavMesh([ground, walls], parameters)
- Check the array before calling: if (meshes.length === 0) throw/return; e.g. verify your scene query actually matched (console.log(meshes.length))
- Verify mesh collection logic — tag names, predicates, enabled/pickable filters, and that async loads resolved before generation
- If geometry is meant to come from the scene, gather it explicitly: const meshes = scene.meshes.filter(m => m.isEnabled() && m.geometry)
Example fix
// before
const meshes = scene.getMeshesByTags("nav"); // matches nothing
plugin.createNavMesh(meshes, parameters); // throws
// after
const meshes = scene.getMeshesByTags("nav");
if (meshes.length === 0) {
meshes.push(ground); // or fix the tag assignment on your meshes
}
plugin.createNavMesh(meshes, parameters); Defensive patterns
Strategy: validation
Validate before calling
const meshes = scene.meshes.filter(m => m.isEnabled() && m.geometry);
if (meshes.length === 0) {
throw new Error("createNavMesh called with no meshes");
}
plugin.createNavMesh(meshes, parameters); Type guard
function hasMeshes(meshes: unknown): meshes is Array<Mesh> {
return Array.isArray(meshes) && meshes.length > 0;
} Try / catch
try {
const result = GenerateNavMesh(meshes, parameters);
} catch (e) {
if (e instanceof Error && e.message.includes("At least one mesh is needed")) {
// fix mesh collection; skip or retry with a fallback mesh
}
} Prevention
- Always assert meshes.length > 0 before calling createNavMesh
- Log the mesh-collection query result during development to catch filters that match nothing
- Generate the nav mesh only after scene.whenReadyAsync() resolves
- Never pass a copy/filter of the mesh array without checking it first
When it happens
Trigger: Calling GenerateNavMesh([], parameters) directly, or via a navigation plugin path that forwards an empty mesh array — e.g. collecting meshes with a predicate/filter (scene.getMeshesByTags, pickable/enabled filters) that matches nothing, awaiting mesh loading that failed so the array stays empty, or constructing the array conditionally and pushing nothing.
Common situations: Tag-based or predicate-based mesh selection returning zero results; scene meshes filtered out because they are disabled/not pickable; async mesh load races where generation runs before meshes are added; refactored code passing a filtered copy of the array instead of the original; calling the plugin before any level geometry exists.
Related errors
- At least one mesh is needed to create the nav mesh.
- Unable to create navmesh. No navMesh or navMeshQuery returne
- Unable to get nav mesh. No vertices or indices.
- Unable to generateSoloNavMesh: ${result.error}
- Unable to generate navMesh: ${e}
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/8b0679e7a347bc3b.
Report an issue: GitHub.