egametang/ET · error · IOException
Invalid number of verts per poly {header.maxVertsPerPoly}
Error message
Invalid number of verts per poly {header.maxVertsPerPoly} What it means
Thrown by DtMeshSetReader.Read when the parsed set header has maxVertsPerPoly <= 0. This value (nvp) defines the max polygon size for the navmesh; a non-positive value is invalid. It usually means the caller passed -1 (the default) but the set file did not embed the field (only NAVMESHSET_VERSION_RECAST4J embeds it).
Source
Thrown at Packages/cn.etetet.recast/Scripts/Core/Share/Detour/Io/DtMeshSetReader.cs:65
return Read(bb, maxVertPerPoly, true);
}
public DtNavMesh Read(BinaryReader @is)
{
return Read(IOUtils.ToByteBuffer(@is));
}
public DtNavMesh Read(RcByteBuffer bb)
{
return Read(bb, -1, false);
}
DtNavMesh Read(RcByteBuffer bb, int maxVertPerPoly, bool is32Bit)
{
NavMeshSetHeader header = ReadHeader(bb, maxVertPerPoly);
if (header.maxVertsPerPoly <= 0)
{
throw new IOException("Invalid number of verts per poly " + header.maxVertsPerPoly);
}
bool cCompatibility = header.version == NavMeshSetHeader.NAVMESHSET_VERSION;
DtNavMesh mesh = new DtNavMesh(header.option, header.maxVertsPerPoly);
ReadTiles(bb, is32Bit, header, cCompatibility, mesh);
return mesh;
}
private NavMeshSetHeader ReadHeader(RcByteBuffer bb, int maxVertsPerPoly)
{
NavMeshSetHeader header = new NavMeshSetHeader();
header.magic = bb.GetInt();
if (header.magic != NavMeshSetHeader.NAVMESHSET_MAGIC)
{
header.magic = IOUtils.SwapEndianness(header.magic);
if (header.magic != NavMeshSetHeader.NAVMESHSET_MAGIC)
{
throw new IOException("Invalid magic " + header.magic);View on GitHub (pinned to 5cab01f7a8)
Solutions
- Call Read(bb, maxVertPerPoly, is32Bit) with a valid nvp (typically 6, matching DT_VERTS_PER_POLYGON) when the file does not embed it.
- Ensure exported set files use a version that embeds maxVertsPerPoly, or always supply it at load time.
- Validate the value is > 0 before constructing the DtNavMesh.
Example fix
// before var mesh = setReader.Read(bb); // default nvp = -1 -> throws // after const int NVP = 6; var mesh = setReader.Read(bb, NVP, false);
Defensive patterns
Strategy: validation
Validate before calling
int nvp = ResolveNvp(); // from config or known good default if (nvp <= 0) nvp = 6; // DT_VERTS_PER_POLYGON var mesh = setReader.Read(bb, nvp, false);
Type guard
static bool IsValidNvp(int nvp) => nvp > 0;
Try / catch
try { var mesh = setReader.Read(bb, nvp, is32Bit); }
catch (IOException e) when (e.Message.Contains("verts per poly"))
{ /* supply explicit nvp and retry */ } Prevention
- Always pass an explicit positive nvp (typically 6) when loading non-recast4J set files.
- Export set files in a version that embeds maxVertsPerPoly if you rely on the convenience overload.
- Validate nvp > 0 before constructing the DtNavMesh.
When it happens
Trigger: Calling Read(bb) with the no-nvp overload on a set file whose version is not NAVMESHSET_VERSION_RECAST4J, so maxVertsPerPoly stays at the default -1; passing maxVertPerPoly <= 0 explicitly.
Common situations: Loading a standard (non-recast4j) navmesh set through the convenience overload that does not supply nvp; misconfiguration of the loader pipeline.
Related errors
- Invalid magic
- Invalid version {header.version}
- Invalid magic {header.magic}
- Invalid version {header.version}
- Could not find tile
AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13).
Data as JSON: /api/errors/80374f7972b90d6e.
Report an issue: GitHub.