egametang/ET · critical · Exception

pathfinding ptr is zero: {self.Scene().Name}

Error message

pathfinding ptr is zero: {self.Scene().Name}

What it means

The Find(start, target, result) method guards against a null navMesh field. Because Destroy() sets navMesh to null, this fires when Find is called on a PathfindingComponent that was destroyed, or one whose Awake failed (so navMesh was never assigned).

Source

Thrown at Packages/cn.etetet.recast/Scripts/Hotfix/Share/PathfindingComponentSystem.cs:41

            }
            
            self.filter = new DtQueryDefaultFilter();
            self.query = new DtNavMeshQuery(self.navMesh);
        }

        [EntitySystem]
        private static void Destroy(this PathfindingComponent self)
        {
            self.Name = string.Empty;
            self.navMesh = null;
        }
        
        public static void Find(this PathfindingComponent self, float3 start, float3 target, List<float3> result)
        {
            if (self.navMesh == null)
            {
                Log.Debug("寻路| Find 失败 pathfinding ptr is zero");
                throw new Exception($"pathfinding ptr is zero: {self.Scene().Name}");
            }

            RcVec3f startPos = new(-start.x, start.y, start.z);
            RcVec3f endPos = new(-target.x, target.y, target.z);

            long startRef;
            long endRef;
            RcVec3f startPt;
            RcVec3f endPt;
            
            self.query.FindNearestPoly(startPos, self.extents, self.filter, out startRef, out startPt, out _);
            self.query.FindNearestPoly(endPos, self.extents, self.filter, out endRef, out endPt, out _);
            
            self.query.FindPath(startRef, endRef, startPt, endPt, self.filter, ref self.polys, new DtFindPathOption(0, float.MaxValue));

            if (0 >= self.polys.Count)
            {
                return;

View on GitHub (pinned to 5cab01f7a8)

Solutions

  1. Re-acquire the PathfindingComponent via EntityRef after any await and null-check before calling Find.
  2. Ensure no pathfinding requests are queued after scene/entity destruction (cancel timers / pending work).
  3. Guard call sites: check the entity/component is not disposed before invoking Find.
  4. Fix destroy ordering so pathfinding users are torn down before the navmesh component.

Example fix

// before: stale ref after await
EntityRef<PathfindingComponent> navRef = comp;
await ...;
comp.Find(start, target, result);
// after: re-acquire and validate
EntityRef<PathfindingComponent> navRef = comp;
await ...;
comp = navRef;
if (comp == null || comp.IsDisposed) return;
comp.Find(start, target, result);
Defensive patterns

Strategy: type-guard

Type guard

static bool CanPathfind(this PathfindingComponent c) => c != null && !c.IsDisposed && c.navMesh != null;

Prevention

When it happens

Trigger: Calling entity.FindPath / PathfindingComponent.Find() on a component whose self.navMesh is null. This includes: post-Destroy usage, components created without a successful Awake (see error 309), or logic that retained a stale component reference after teardown.

Common situations: EntityRef holding a PathfindingComponent across an await during which the entity (and component) was destroyed; scene teardown ordering where pathfinding requests are still in-flight; a system calling Find without checking component liveness.

Related errors


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