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
- Re-acquire the PathfindingComponent via EntityRef after any await and null-check before calling Find.
- Ensure no pathfinding requests are queued after scene/entity destruction (cancel timers / pending work).
- Guard call sites: check the entity/component is not disposed before invoking Find.
- 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
- Re-acquire PathfindingComponent via EntityRef after every await.
- Cancel pathfinding requests when the owning entity is destroyed.
- Tear down pathfinding users before the navmesh component.
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
- Empty path
- nav load fail: {name}
- ERR_LocationAlreadyLocked
- entity is disposed, instanceid == 0!
- TChannel已经被Dispose, 不能发送消息
AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13).
Data as JSON: /api/errors/a56386b0e7c4b037.
Report an issue: GitHub.