egametang/ET · error · IOException
Invalid magic
Error message
Invalid magic
What it means
Thrown by DtMeshDataReader.Read when the first int of the byte buffer is not the Detour navmesh magic (DT_NAVMESH_MAGIC), even after a trial endianness swap. The magic identifies a valid single-tile navmesh data blob; its absence means the input is not a Detour tile mesh, is truncated, or is a different file type.
Source
Thrown at Packages/cn.etetet.recast/Scripts/Core/Share/Detour/Io/DtMeshDataReader.cs:61
}
public DtMeshData Read32Bit(RcByteBuffer buf, int maxVertPerPoly)
{
return Read(buf, maxVertPerPoly, true);
}
public DtMeshData Read(RcByteBuffer buf, int maxVertPerPoly, bool is32Bit)
{
DtMeshData data = new DtMeshData();
DtMeshHeader header = new DtMeshHeader();
data.header = header;
header.magic = buf.GetInt();
if (header.magic != DtMeshHeader.DT_NAVMESH_MAGIC)
{
header.magic = IOUtils.SwapEndianness(header.magic);
if (header.magic != DtMeshHeader.DT_NAVMESH_MAGIC)
{
throw new IOException("Invalid magic");
}
buf.Order(buf.Order() == RcByteOrder.BIG_ENDIAN ? RcByteOrder.LITTLE_ENDIAN : RcByteOrder.BIG_ENDIAN);
}
header.version = buf.GetInt();
if (header.version != DtMeshHeader.DT_NAVMESH_VERSION)
{
if (header.version < DtMeshHeader.DT_NAVMESH_VERSION_RECAST4J_FIRST
|| header.version > DtMeshHeader.DT_NAVMESH_VERSION_RECAST4J_LAST)
{
throw new IOException("Invalid version " + header.version);
}
}
bool cCompatibility = header.version == DtMeshHeader.DT_NAVMESH_VERSION;
header.x = buf.GetInt();
header.y = buf.GetInt();View on GitHub (pinned to 5cab01f7a8)
Solutions
- Use DtMeshSetReader for whole navmesh set files and DtMeshDataReader only for individual tile blobs.
- Verify the file is non-empty and begins with the expected 4-byte magic before reading.
- Re-export the navmesh data with a supported tool (DotRecast/recast) and confirm it loads round-trip.
- Check asset import/pipeline for truncation or re-encoding.
Example fix
// before var data = meshDataReader.Read(buf, maxVertPerPoly, is32Bit); // wrong file // after // pick reader by file kind var mesh = setReader.Read(buf);
Defensive patterns
Strategy: validation
Validate before calling
// Peek the first 4 bytes before handing the buffer to the reader.
int magic = BitConverter.ToInt32(chunk, 0);
if (magic != DtMeshHeader.DT_NAVMESH_MAGIC &&
IOUtils.SwapEndianness(magic) != DtMeshHeader.DT_NAVMESH_MAGIC)
throw new InvalidDataException("Not a Detour tile mesh"); Type guard
static bool IsDetourTileMagic(int m)
=> m == DtMeshHeader.DT_NAVMESH_MAGIC || IOUtils.SwapEndianness(m) == DtMeshHeader.DT_NAVMESH_MAGIC; Try / catch
try { var data = meshDataReader.Read(buf, nvp, is32Bit); }
catch (IOException e) when (e.Message.Contains("Invalid magic"))
{ /* try set reader, or reject file */ } Prevention
- Match the reader to the file kind (single tile vs set).
- Validate the magic bytes before reading.
- Re-export corrupt assets from source.
- Confirm the asset pipeline does not truncate or re-encode files.
When it happens
Trigger: Loading a file that is a navmesh set (.navmesh) through the single-tile reader; passing a raw OBJ/geometry buffer; a truncated or zero-padded file; endianness from an unsupported source.
Common situations: Pointing the reader at a whole-set file instead of a tile file; corrupt download/asset; reading an asset produced by an incompatible toolchain.
Related errors
- Invalid magic {header.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/45b53d99544bdc39.
Report an issue: GitHub.