egametang/ET · error · Exception

Could not allocate a tile

Error message

Could not allocate a tile

What it means

DtNavMesh.AddTile with lastRef == 0 allocates a fresh tile from the free-list (availableTiles). When the list is empty, all m_maxTiles slots are in use and no tile can be assigned; the add fails. This is a capacity limit on the DtNavMesh, set at construction via the mesh params maxTiles.

Source

Thrown at Packages/cn.etetet.recast/Scripts/Core/Share/Detour/DtNavMesh.cs:476

        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
            {
                // Try to relocate the tile to specific index with same salt.
                int tileIndex = DecodePolyIdTile(lastRef);
                if (tileIndex >= m_maxTiles)
                {
                    throw new Exception("Tile index too high");
                }

                // Try to find the specific tile id from the free list.
                DtMeshTile target = m_tiles[tileIndex];
                // Remove from freelist

View on GitHub (pinned to 5cab01f7a8)

Solutions

  1. Increase the DtNavMesh maxTiles (passed at DtNavMesh construction) above peak live tile count.
  2. Ensure RemoveTile is called on unload so slots return to the free-list.
  3. Track live tile count and shed/defer loads when near capacity.

Example fix

// before: mesh built with too few tiles
var mesh = new DtNavMesh(new DtNavMeshParams { ... maxTiles = 512 });
foreach (var d in allData) mesh.AddTile(d, 0, 0); // overflows

// after: size to peak, and remove before re-adding
var mesh = new DtNavMesh(new DtNavMeshParams { ... maxTiles = 4096 });
Defensive patterns

Strategy: validation

Validate before calling

if (mesh.GetTileCount() >= meshMaxTiles)
    throw new InvalidOperationException(
        $"DtNavMesh at capacity ({mesh.GetTileCount()}/{meshMaxTiles}); remove a tile or raise maxTiles.");
mesh.AddTile(data, flags, 0);

Try / catch

try { return mesh.AddTile(data, flags, 0); }
catch (Exception e) when (e.Message == "Could not allocate a tile")
{ /* evict a tile, then retry once, or report capacity */ }

Prevention

When it happens

Trigger: Calling AddTile(data, flags, 0) more than maxTiles times without matching RemoveTile; loading a navmesh whose tile count exceeds the mesh's configured maxTiles.

Common situations: maxTiles sized too small for the world; tiles added but never removed on unload; streaming that exceeds the pre-allocated slot count at peak.

Related errors


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