egametang/ET · critical · Exception
rcBuildPolyMesh: The resulting mesh has too many polygons {m
Error message
rcBuildPolyMesh: The resulting mesh has too many polygons {mesh.npolys} (max {MAX_MESH_VERTS_POLY}). Data can be corrupted. What it means
The post-condition check at RecastMesh.cs:1206 verifies mesh.npolys does not exceed MAX_MESH_VERTS_POLY (65535) at the end of the primary rcBuildPolyMesh path. Exceeding it means the 16-bit polygon index fields overflowed, so the returned mesh may be corrupted.
Source
Thrown at Packages/cn.etetet.recast/Scripts/Core/Share/Recast/RecastMesh.cs:1206
mesh.polys[p + nvp + j] = 0x8000 | 2;
else if (mesh.verts[va + 2] == 0 && mesh.verts[vb + 2] == 0)
mesh.polys[p + nvp + j] = 0x8000 | 3;
}
}
}
// Just allocate the mesh flags array. The user is resposible to fill it.
mesh.flags = new int[mesh.npolys];
if (mesh.nverts > MAX_MESH_VERTS_POLY)
{
throw new Exception("rcBuildPolyMesh: The resulting mesh has too many vertices " + mesh.nverts
+ " (max " + MAX_MESH_VERTS_POLY + "). Data can be corrupted.");
}
if (mesh.npolys > MAX_MESH_VERTS_POLY)
{
throw new Exception("rcBuildPolyMesh: The resulting mesh has too many polygons " + mesh.npolys
+ " (max " + MAX_MESH_VERTS_POLY + "). Data can be corrupted.");
}
return mesh;
}
/// @see rcAllocPolyMesh, rcPolyMesh
public static RcPolyMesh MergePolyMeshes(RcTelemetry ctx, RcPolyMesh[] meshes, int nmeshes)
{
if (nmeshes == 0 || meshes == null)
return null;
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_MERGE_POLYMESH);
RcPolyMesh mesh = new RcPolyMesh();
mesh.nvp = meshes[0].nvp;
mesh.cs = meshes[0].cs;
mesh.ch = meshes[0].ch;View on GitHub (pinned to 5cab01f7a8)
Solutions
- Tile the navmesh (rcConfig.tileSize) so each tile's polygon count stays far below 65535.
- Raise maxVertsPerPoly to reduce polygon count per contour.
- Raise cellSize / contourSimplificationError to coarsen geometry.
- If building a merged mesh (MergePolyMeshes), confirm inputs aren't already near the limit.
Defensive patterns
Strategy: validation
Try / catch
try { rcBuildPolyMesh(ctx, cset, nvp, out mesh); }
catch (Exception e) when (e.Message.Contains("too many polygons") && e.Message.Contains("Data can be corrupted")) {
Log.Error($"Corrupt polymesh: {e.Message}");
// discard mesh, re-bake with coarser config or smaller tiles
} Prevention
- Cap per-tile polygon count in bake config.
- Never consume a mesh that triggered a 'Data can be corrupted' throw.
- Run automated bake-size assertions on level content.
When it happens
Trigger: Fires immediately after the nverts check at :1200 in the same finalization block, when mesh.npolys > 65535 after all polygon storage is complete.
Common situations: Massively polygon-heavy navmesh from a huge or untiled level; low maxVertsPerPoly combined with dense contours; often co-occurs with error 302. Indicates the conservative maxTris guard (301) was not the binding constraint but the final 16-bit cap was.
Related errors
- rcBuildPolyMesh: Too many polygons {mesh.npolys} (max:{maxTr
- rcBuildPolyMesh: The resulting mesh has too many vertices {m
- rcBuildPolyMesh: Too many vertices {maxVertices}
- addEdge: Too many edges ({edges.Count / 4}/{maxEdges}).
- rcBuildPolyMeshDetail: Shrinking triangle count from {ntris}
AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13).
Data as JSON: /api/errors/b6ec65cfe79105b4.
Report an issue: GitHub.