{"record":{"id":"22e80c002f14558b","repo":"BabylonJS/Babylon.js","slug":"unable-to-generate-navmesh-e","errorCode":null,"errorMessage":"Unable to generate navMesh: ${e}","messagePattern":"Unable to generate navMesh: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/addons/src/navigation/generator/generator.worker.ts","lineNumber":47,"sourceCode":"         * @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);\n                    const navMeshData = BuildFromNavmeshData(navMeshArray);\n                    workerOptions.completion(navMeshData.navMesh, navMeshData.navMeshQuery, undefined);\n                    return;\n                }\n            }\n","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/addons/src/navigation/generator/generator.worker.ts#L29-L65","documentation":"The worker's onmessage handler in GenerateNavMeshWithWorker() (generator.worker.ts:47) throws when the worker reports success === false, embedding the whole event object in the message. This means generation failed inside the worker — the same class of failure as error 12 (Recast rejected the geometry or config) — but surfaced asynchronously through the message channel. Note the thrown error is thrown inside the onmessage callback, so it lands in the worker message handler's context, not the caller's await chain.","triggerScenarios":"Worker-side Recast generation returns success:false: invalid config (bad cellSize/agent values, tileSize outside 32–64 with maxObstacles), wrong triangle winding (doNotReverseIndices mismatch), degenerate geometry, or geometry incompatible with tile bounds. Any worker-side error, including WASM memory failures, is reported via this message.","commonSituations":"Large scenes blowing the worker's WASM memory limits during generation; config copied from a single-threaded setup that doesn't suit the tiled/tile-cache path; winding flipped by an exporter; diagnosing is harder because the message contains the event object rather than a clean error string.","solutions":["Inspect e.data.error (or stringify the event) to get the worker-side Recast failure reason and fix that specific issue","Match the fixes from the single-threaded path: correct doNotReverseIndices winding, tileSize 32–64 with maxObstacles > 0, sane config values for your scene scale","Reduce scene complexity/geometry size if the worker hits WASM memory limits; generate fewer tiles or smaller meshes","Wrap createNavMeshAsync in try/catch AND note the throw occurs in onmessage — ensure your plugin surfaces worker failures as promise rejections you can catch"],"exampleFix":"// before\nworkerOptions.worker.onmessage = (e) => {\n    if ((e as any).data?.success === false) {\n        throw new Error(`Unable to generate navMesh: ${e}`); // opaque event\n    }\n};\n\n// after (diagnosing)\nworkerOptions.worker.onmessage = (e) => {\n    if ((e as any).data?.success === false) {\n        console.error(\"Worker navmesh failure:\", (e as any).data?.error);\n        // fix config, e.g.:\n        // parameters.tileSize = 64; parameters.doNotReverseIndices = false;\n    }\n};","handlingStrategy":"try-catch","validationCode":"workerOptions.worker.onerror = (err) => console.error(\"navmesh worker error:\", err);\nworkerOptions.worker.onmessage = (e) => {\n    if ((e as any).data?.success === false) {\n        console.error(\"Recast failure detail:\", (e as any).data?.error);\n    }\n};\n// validate parameters before sending to the worker\nif ((parameters.maxObstacles ?? 0) > 0 && ((parameters.tileSize ?? 0) < 32 || (parameters.tileSize ?? 0) > 64)) {\n    throw new Error(\"tileSize must be 32-64 with maxObstacles > 0\");\n}","typeGuard":"function isWorkerFailure(e: MessageEvent): e is MessageEvent & { data: { success: false; error: string } } {\n    return (e as any).data?.success === false && typeof (e as any).data?.error === \"string\";\n}","tryCatchPattern":"try {\n    await plugin.createNavMeshAsync(meshes, parameters);\n} catch (e) {\n    if (e instanceof Error && e.message.includes(\"Unable to generate navMesh\")) {\n        console.error(\"Worker-side generation failed; check config/winding/geometry\", e.message);\n        // retry with corrected parameters or fall back to single-threaded generation\n    }\n}","preventionTips":["Log e.data (not the whole event) from the worker message to see the real Recast error","Reuse the same config validation as the single-threaded path before sending work to the worker","Monitor worker WASM memory for large scenes; shrink geometry or tile counts if generation dies in the worker","Provide a fallback to GenerateNavMesh (single-threaded) so failures degrade gracefully"],"tags":["navigation","recast","navmesh","worker","async"],"backgroundTag":"navmesh-generation-failed","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}