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

  1. Use DtMeshSetReader for whole navmesh set files and DtMeshDataReader only for individual tile blobs.
  2. Verify the file is non-empty and begins with the expected 4-byte magic before reading.
  3. Re-export the navmesh data with a supported tool (DotRecast/recast) and confirm it loads round-trip.
  4. 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

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


AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13). Data as JSON: /api/errors/45b53d99544bdc39. Report an issue: GitHub.