egametang/ET · error · Exception
Tile already exists
Error message
Tile already exists
What it means
DtNavMesh.AddTile checks that no tile currently occupies the target (x,y,layer) location via GetTileAt before inserting. If one is already there, adding again would create overlapping geometry and ambiguous lookups, so it refuses. This is a logical duplicate, independent of tile-slot capacity.
Source
Thrown at Packages/cn.etetet.recast/Scripts/Core/Share/Detour/DtNavMesh.cs:466
/// reference it had previously used. In this case the #long's for the
/// tile will be restored to the same values they were before the tile was
/// removed.
///
/// The nav mesh assumes exclusive access to the data passed and will make
/// changes to the dynamic portion of the data. For that reason the data
/// should not be reused in other nav meshes until the tile has been successfully
/// removed from this nav mesh.
///
/// @see dtCreateNavMeshData, #removeTile
public long AddTile(DtMeshData data, int flags, long lastRef)
{
// Make sure the data is in right format.
DtMeshHeader header = data.header;
// Make sure the location is free.
if (GetTileAt(header.x, header.y, header.layer) != null)
{
throw new Exception("Tile already exists");
}
// Allocate a tile.
DtMeshTile tile = null;
if (lastRef == 0)
{
// Make sure we could allocate a tile.
if (0 == availableTiles.Count)
{
throw new Exception("Could not allocate a tile");
}
tile = availableTiles.First?.Value;
availableTiles.RemoveFirst();
m_tileCount++;
}
else
{View on GitHub (pinned to 5cab01f7a8)
Solutions
- Remove the existing tile at (x,y,layer) before adding (call RemoveTile on the prior ref).
- Guard with GetTileAt(x,y,layer) == null before AddTile.
- Track loaded tile locations in a set to avoid duplicate load requests.
Example fix
// before
mesh.AddTile(data, flags, lastRef);
// after
if (mesh.GetTileAt(data.header.x, data.header.y, data.header.layer) != null)
mesh.RemoveTile(mesh.GetTileRefAt(data.header.x, data.header.y, data.header.layer));
mesh.AddTile(data, flags, lastRef); Defensive patterns
Strategy: validation
Validate before calling
if (mesh.GetTileAt(data.header.x, data.header.y, data.header.layer) != null)
throw new InvalidOperationException(
$"tile already loaded at ({data.header.x},{data.header.y},{data.header.layer})");
mesh.AddTile(data, flags, lastRef); Try / catch
try { return mesh.AddTile(data, flags, lastRef); }
catch (Exception e) when (e.Message == "Tile already exists")
{ /* remove existing then retry, or skip as duplicate */ } Prevention
- Remove the tile at (x,y,layer) before re-adding.
- Guard AddTile with GetTileAt == null.
- Track loaded locations in a set to avoid duplicate loads.
When it happens
Trigger: Calling AddTile for a location already loaded; re-adding a tile after a failed/unclean removal; streaming that loads the same (x,y,layer) twice; layered tiles reusing a layer index that is still present.
Common situations: Reload without prior remove; double-load from two streaming sources; layer index collision in multi-layer setups; additive scene loading that overlaps existing tiles.
Related errors
- Invalid tile ref
- Tile index too high
- ERR_LocationLockTokenMismatch
- Item cannot be null
- MethodHook:targetMethod and replacementMethod and proxyMetho
AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13).
Data as JSON: /api/errors/ec295f6df9aefd6b.
Report an issue: GitHub.