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

  1. Pass at least one mesh with geometry: const plugin = await CreateNavigationPluginAsync(); plugin.createNavMesh([ground, walls], parameters)
  2. Check the array before calling: if (meshes.length === 0) throw/return; e.g. verify your scene query actually matched (console.log(meshes.length))
  3. Verify mesh collection logic — tag names, predicates, enabled/pickable filters, and that async loads resolved before generation
  4. 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

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


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