{"record":{"id":"a5bd384082af2cbd","repo":"egametang/ET","slug":"invalid-tile-ref","errorCode":null,"errorMessage":"Invalid tile ref","messagePattern":"Invalid tile ref","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"Packages/cn.etetet.recast/Scripts/Core/Share/Detour.TileCache/DtTileCache.cs","lineNumber":290,"sourceCode":"            // Init tile.\n            tile.header = header;\n            tile.data = data;\n            tile.compressed = Align4(buf.Position());\n            tile.flags = flags;\n\n            return GetTileRef(tile);\n        }\n\n        private int Align4(int i)\n        {\n            return (i + 3) & (~3);\n        }\n\n        public void RemoveTile(long refs)\n        {\n            if (refs == 0)\n            {\n                throw new Exception(\"Invalid tile ref\");\n            }\n\n            int tileIndex = DecodeTileIdTile(refs);\n            int tileSalt = DecodeTileIdSalt(refs);\n            if (tileIndex >= m_params.maxTiles)\n            {\n                throw new Exception(\"Invalid tile index\");\n            }\n\n            DtCompressedTile tile = m_tiles[tileIndex];\n            if (tile.salt != tileSalt)\n            {\n                throw new Exception(\"Invalid tile salt\");\n            }\n\n            // Remove tile from hash lookup.\n            int h = DtNavMesh.ComputeTileHash(tile.header.tx, tile.header.ty, m_tileLutMask);\n            DtCompressedTile prev = null;","sourceCodeStart":272,"sourceCodeEnd":308,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.recast/Scripts/Core/Share/Detour.TileCache/DtTileCache.cs#L272-L308","documentation":"DtTileCache.RemoveTile refuses a reference of 0 because zero is the library's sentinel for 'no tile' (a real tile ref always carries a non-zero salt/index encoding). Passing 0 means the caller never had, or already lost, the reference and there is nothing to remove.","triggerScenarios":"Calling RemoveTile(0) directly; passing a ref returned as 0 from a failed AddTile/GetTileRef; removing a tile whose ref was never captured or was reset to default.","commonSituations":"Unloading a tile from a ref field that defaulted to 0 because load failed earlier; double-unload where the second call still holds the now-zeroed ref; code that assumes GetTileRef always returns a valid handle.","solutions":["Guard the call: only RemoveTile when refs != 0.","Reset your stored ref to 0 after a successful RemoveTile so a repeated unload is a no-op.","Log when you attempt to remove a 0 ref so stale unload requests are visible."],"exampleFix":"// before\ncache.RemoveTile(storedRef);\n\n// after\nif (storedRef != 0)\n{\n    cache.RemoveTile(storedRef);\n    storedRef = 0;\n}","handlingStrategy":"validation","validationCode":"if (tileRef == 0) return; // nothing to remove\ncache.RemoveTile(tileRef);","typeGuard":"static bool IsValidTileRef(long r) => r != 0;","tryCatchPattern":null,"preventionTips":["Zero your stored ref after a successful RemoveTile.","Guard every RemoveTile call with a non-zero check.","Log attempts to remove a zero ref to catch missing-load bugs upstream."],"tags":["validation","detour-tilecache","api-misuse"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}