egametang/ET · error · IOException
Invalid version
Error message
Invalid version
What it means
After the set magic passes, DtTileCacheReader.Read checks the version int. It accepts the current TILECACHESET_VERSION (1) or the legacy recast4j version (0x8801); any other value throws 'Invalid version'. The cCompatibility flag is then derived from which version matched, so a truly unknown version cannot be safely parsed.
Source
Thrown at Packages/cn.etetet.recast/Scripts/Core/Share/Detour.TileCache/Io/DtTileCacheReader.cs:64
DtTileCacheSetHeader header = new DtTileCacheSetHeader();
header.magic = bb.GetInt();
if (header.magic != DtTileCacheSetHeader.TILECACHESET_MAGIC)
{
header.magic = IOUtils.SwapEndianness(header.magic);
if (header.magic != DtTileCacheSetHeader.TILECACHESET_MAGIC)
{
throw new IOException("Invalid magic");
}
bb.Order(bb.Order() == RcByteOrder.BIG_ENDIAN ? RcByteOrder.LITTLE_ENDIAN : RcByteOrder.BIG_ENDIAN);
}
header.version = bb.GetInt();
if (header.version != DtTileCacheSetHeader.TILECACHESET_VERSION)
{
if (header.version != DtTileCacheSetHeader.TILECACHESET_VERSION_RECAST4J)
{
throw new IOException("Invalid version");
}
}
bool cCompatibility = header.version == DtTileCacheSetHeader.TILECACHESET_VERSION;
header.numTiles = bb.GetInt();
header.meshParams = paramReader.Read(bb);
header.cacheParams = ReadCacheParams(bb, cCompatibility);
DtNavMesh mesh = new DtNavMesh(header.meshParams, maxVertPerPoly);
IRcCompressor comp = _compFactory.Create(cCompatibility ? 0 : 1);
DtTileCacheStorageParams storageParams = new DtTileCacheStorageParams(bb.Order(), cCompatibility);
DtTileCache tc = new DtTileCache(header.cacheParams, storageParams, mesh, comp, meshProcessor);
// Read tiles.
for (int i = 0; i < header.numTiles; ++i)
{
long tileRef = bb.GetInt();
int dataSize = bb.GetInt();
if (tileRef == 0 || dataSize == 0)
{View on GitHub (pinned to 5cab01f7a8)
Solutions
- Re-export the tile-cache set with the consuming DotRecast version.
- Keep producer and consumer library versions aligned in CI/asset baking.
- If migrating from recast4j, confirm the file carries version 0x8801 so the legacy path is used.
Example fix
// before: set baked on an incompatible version
var tc = reader.Read(bb, maxVertPerPoly, proc);
// after: re-bake with current version, or verify version up front
int v = bb.GetInt();
if (v != DtTileCacheSetHeader.TILECACHESET_VERSION
&& v != DtTileCacheSetHeader.TILECACHESET_VERSION_RECAST4J)
throw new InvalidDataException($"unsupported tilecache set version {v}"); Defensive patterns
Strategy: try-catch
Validate before calling
int v = bb.GetInt(); // after magic
if (v != DtTileCacheSetHeader.TILECACHESET_VERSION
&& v != DtTileCacheSetHeader.TILECACHESET_VERSION_RECAST4J)
throw new InvalidDataException($"unsupported tile-cache set version {v}"); Try / catch
try { return reader.Read(bb, maxVertPerPoly, proc); }
catch (IOException e) when (e.Message == "Invalid version")
{ /* re-export the set with the current version */ } Prevention
- Align producer and consumer DotRecast versions in baking and loading.
- Re-bake the set after a library upgrade.
- For recast4j imports, confirm the file carries version 0x8801.
When it happens
Trigger: Loading a tile-cache set written by a DotRecast/recast4j version whose set version is neither 1 nor 0x8801; bytes whose version int is corrupt after a valid magic.
Common situations: Cross-version asset loading after a format change; hand-edited or partially overwritten files; producer and consumer on mismatched library versions.
Related errors
AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13).
Data as JSON: /api/errors/55022d19acbe6d97.
Report an issue: GitHub.