egametang/ET · error · IOException
Invalid magic {header.magic}
Error message
Invalid magic {header.magic} What it means
Thrown by DtMeshSetReader.ReadHeader when the first int is not the navmesh-set magic (NAVMESHSET_MAGIC) even after an endianness swap. The set magic marks a multi-tile navmesh set file; its absence means the input is not a set file (e.g., it is a single tile mesh, an OBJ, or corrupt).
Source
Thrown at Packages/cn.etetet.recast/Scripts/Core/Share/Detour/Io/DtMeshSetReader.cs:83
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);
}
bb.Order(bb.Order() == RcByteOrder.BIG_ENDIAN ? RcByteOrder.LITTLE_ENDIAN : RcByteOrder.BIG_ENDIAN);
}
header.version = bb.GetInt();
if (header.version != NavMeshSetHeader.NAVMESHSET_VERSION && header.version != NavMeshSetHeader.NAVMESHSET_VERSION_RECAST4J_1
&& header.version != NavMeshSetHeader.NAVMESHSET_VERSION_RECAST4J)
{
throw new IOException("Invalid version " + header.version);
}
header.numTiles = bb.GetInt();
header.option = paramReader.Read(bb);
header.maxVertsPerPoly = maxVertsPerPoly;
if (header.version == NavMeshSetHeader.NAVMESHSET_VERSION_RECAST4J)
{
header.maxVertsPerPoly = bb.GetInt();View on GitHub (pinned to 5cab01f7a8)
Solutions
- Use DtMeshDataReader for single-tile blobs and DtMeshSetReader for set files.
- Verify the file header bytes match NAVMESHSET_MAGIC before reading.
- Re-export the set file from a supported tool and confirm round-trip loading.
Example fix
// before var mesh = setReader.Read(bb); // file is actually a single tile // after var data = meshDataReader.Read(bb, nvp, is32Bit); var mesh = new DtNavMesh(); mesh.AddTile(data, 0, 0);
Defensive patterns
Strategy: validation
Validate before calling
int magic = BitConverter.ToInt32(chunk, 0);
if (magic != NavMeshSetHeader.NAVMESHSET_MAGIC &&
IOUtils.SwapEndianness(magic) != NavMeshSetHeader.NAVMESHSET_MAGIC)
throw new InvalidDataException("Not a navmesh set file"); Type guard
static bool IsSetMagic(int m)
=> m == NavMeshSetHeader.NAVMESHSET_MAGIC || IOUtils.SwapEndianness(m) == NavMeshSetHeader.NAVMESHSET_MAGIC; Try / catch
try { var mesh = setReader.Read(bb); }
catch (IOException e) when (e.Message.Contains("Invalid magic"))
{ /* fall back to single-tile reader or reject */ } Prevention
- Use the set reader only for set files; the single-tile reader for tile blobs.
- Validate the set magic before reading.
- Confirm asset integrity if magic is missing.
When it happens
Trigger: Loading a single-tile DtMeshData blob through the set reader; pointing at a non-navmesh file; a truncated or re-encoded asset.
Common situations: Wrong reader selected for the file kind; corrupt asset; wrong file extension mapping.
Related errors
- Invalid magic
- Invalid magic
- Invalid magic
- Invalid version {header.version}
- Invalid number of verts per poly {header.maxVertsPerPoly}
AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13).
Data as JSON: /api/errors/c8d36e8b721c30a0.
Report an issue: GitHub.