GraphUpdate & NavmeshCut interaction causing errors

  • A* version: [5.2.4]
  • Unity version: [6000.0.23f1]

Hey! I’ve been using A* in a project for some time now, and overall it’s been great! The other day we upgraded from a much earlier version to the latest version, and since then we’ve run into some recurring errors.
This might be similar to the error observed in This Topic, but its different in a number of ways so I decided to start a new thread.

So for our project, we’re using Recast graphs on a procedurally generated area, then performing graph updates on small areas when obstacles are destroyed. Sometimes the destroyed obstacles instantiate an object that has a NavmeshCut component. After playing for a bit, we keep getting one of several errors that cause the pathfinding to fail. These errors sometimes happen by themselves, or we’ll see several happen in rapid succession. We’re currently using Unity 6, but also observed the bugs in Unity 2022.3.5. We did a fresh reinstall of A*, and I’ve checked to make sure the Burst and Collections packages are up to date.

The errors we’ve caught are as follows:

MINOR ERROR - When this one happens, pathfinding is still able to run, and there are no obvious issues with the gameplay.

Log

Error during cutting
0x00007ff8c648f76e (Unity) Stacktrace::GetStacktrace
0x00007ff8c49f146a (Unity) DefaultBurstRuntimeLogCallback
0x00007ff8c42f56fa (Unity) BurstCompilerService_CUSTOM_RuntimeLog
0x00007ff8de8037b3 (97dc418598cced24022449f7263d673) Pathfinding.Graphs.Navmesh.TileHandler.Pathfinding.Graphs.Navmesh.CutTiles_00000ADB$BurstDirectCall.Invoke (at C:/Users/brend/OneDrive/Documents/asteroid-rancher-2021/Library/PackageCache/com.unity.burst/.Runtime/unknown/unknown:0)
0x00007ff8de82ee0b (97dc418598cced24022449f7263d673) Unity.Jobs.IJobExtensions.JobStruct`1<Pathfinding.Graphs.Navmesh.TileCutter.JobCutTiles>.Execute(ref Pathfinding.Graphs.Navmesh.TileCutter.JobCutTiles data, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref Unity.Jobs.LowLevel.Unsafe.JobRanges ranges, int jobIndex) → void_a8542dda2b3b28fb6a489532264bb448 from UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null (at C:/Users/brend/OneDrive/Documents/asteroid-rancher-2021/Library/PackageCache/com.unity.burst/.Runtime/unknown/unknown:0)
0x00007ff8de82dcbd (97dc418598cced24022449f7263d673) 21a76e848d144b130c0976e4adfb32af
0x00007ff8c4d3b025 (Unity) ExecuteJob
0x00007ff8c4d3c13d (Unity) ForwardJobToManaged
0x00007ff8c4d38339 (Unity) ujob_execute_job
0x00007ff8c4d3772f (Unity) lane_guts
0x00007ff8c4d3a374 (Unity) worker_thread_routine
0x00007ff8c4f30a0d (Unity) Thread::RunThreadWrapper
0x00007ff989327374 (KERNEL32) BaseThreadInitThunk
0x00007ff989a1cc91 (ntdll) RtlUserThreadStart

MAJOR ERROR 1 - When this one happens, the game continues to run but Pathfinding breaks immediately. Upon ending play mode, Unity completely locks up.

Log

InvalidOperationException: Collection was modified; enumeration operation may not execute.
System.Collections.Generic.List1+Enumerator[T].MoveNextRare () (at <321eb2db7c6d43ea8fc39b54eaca3452>:0) System.Collections.Generic.List1+Enumerator[T].MoveNext () (at <321eb2db7c6d43ea8fc39b54eaca3452>:0)
Pathfinding.Clipper2Lib.ClipperBase.Clear () (at <50640fdcf58843b3843e9b6a7cc87bc3>:0)
Pathfinding.Graphs.Navmesh.TileHandler.CutPolygon (Pathfinding.Collections.UnsafeSpan1[Pathfinding.Graphs.Navmesh.TileHandler+Point64Wrapper]& subject, Pathfinding.Collections.UnsafeSpan1[Pathfinding.Graphs.Navmesh.TileHandler+Point64Wrapper]& contourVertices, Pathfinding.Collections.UnsafeSpan1[Pathfinding.NavmeshCut+ContourBurst]& contours, Pathfinding.Collections.UnsafeSpan1[System.Int32]& contourIndices, Pathfinding.Collections.UnsafeSpan1[System.Int32]& contourIndicesDual, Unity.Collections.LowLevel.Unsafe.UnsafeList1[UnityEngine.Vector2Int]& outputVertices, Unity.Collections.LowLevel.Unsafe.UnsafeList1[System.Int32]& outputVertexCountPerPolygon, System.Int32 mode) (at ./Library/PackageCache/com.arongranberg.astar/Graphs/Navmesh/TileHandler.cs:916) (wrapper native-to-managed) Pathfinding.Graphs.Navmesh.TileHandler.CutPolygon(Pathfinding.Collections.UnsafeSpan1<Pathfinding.Graphs.Navmesh.TileHandler/Point64Wrapper>&,Pathfinding.Collections.UnsafeSpan1<Pathfinding.Graphs.Navmesh.TileHandler/Point64Wrapper>&,Pathfinding.Collections.UnsafeSpan1<Pathfinding.NavmeshCut/ContourBurst>&,Pathfinding.Collections.UnsafeSpan1<int>&,Pathfinding.Collections.UnsafeSpan1&,Unity.Collections.LowLevel.Unsafe.UnsafeList1<UnityEngine.Vector2Int>&,Unity.Collections.LowLevel.Unsafe.UnsafeList1&,int)
UnityEngine.<>c:b__0_0(Object, UnhandledExceptionEventArgs)

MAJOR ERROR 2 - Same as previous error, the game continues to run but Pathfinding breaks immediately. Upon ending play mode, Unity completely locks up.

Log

NullReferenceException: Object reference not set to an instance of an object.
Pathfinding.Clipper2Lib.VertexPool.GetNew (Pathfinding.Clipper2Lib.Point64 pt, Pathfinding.Clipper2Lib.VertexFlags flags, Pathfinding.Clipper2Lib.Vertex prev) (at <50640fdcf58843b3843e9b6a7cc87bc3>:0)
Pathfinding.Clipper2Lib.ClipperEngine.AddPathToVertexList (Pathfinding.Clipper2Lib.SpanCompat1[T] path, Pathfinding.Clipper2Lib.PathType polytype, System.Boolean isOpen, System.Collections.Generic.List1[T] minimaList, System.Collections.Generic.List1[T] vertexList, Pathfinding.Clipper2Lib.VertexPool vertexPool) (at <50640fdcf58843b3843e9b6a7cc87bc3>:0) Pathfinding.Graphs.Navmesh.TileHandler.AddContours (Pathfinding.Clipper2Lib.Clipper64 clipper, Pathfinding.Collections.UnsafeSpan1[Pathfinding.NavmeshCut+ContourBurst]& contours, Pathfinding.Collections.UnsafeSpan1[Pathfinding.Graphs.Navmesh.TileHandler+Point64Wrapper]& contourVertices, Pathfinding.Collections.UnsafeSpan1[System.Int32]& contourIndices) (at ./Library/PackageCache/com.arongranberg.astar/Graphs/Navmesh/TileHandler.cs:887)
Pathfinding.Graphs.Navmesh.TileHandler.CutPolygon (Pathfinding.Collections.UnsafeSpan1[Pathfinding.Graphs.Navmesh.TileHandler+Point64Wrapper]& subject, Pathfinding.Collections.UnsafeSpan1[Pathfinding.Graphs.Navmesh.TileHandler+Point64Wrapper]& contourVertices, Pathfinding.Collections.UnsafeSpan1[Pathfinding.NavmeshCut+ContourBurst]& contours, Pathfinding.Collections.UnsafeSpan1[System.Int32]& contourIndices, Pathfinding.Collections.UnsafeSpan1[System.Int32]& contourIndicesDual, Unity.Collections.LowLevel.Unsafe.UnsafeList1[UnityEngine.Vector2Int]& outputVertices, Unity.Collections.LowLevel.Unsafe.UnsafeList1[System.Int32]& outputVertexCountPerPolygon, System.Int32 mode) (at ./Library/PackageCache/com.arongranberg.astar/Graphs/Navmesh/TileHandler.cs:920) (wrapper native-to-managed) Pathfinding.Graphs.Navmesh.TileHandler.CutPolygon(Pathfinding.Collections.UnsafeSpan1<Pathfinding.Graphs.Navmesh.TileHandler/Point64Wrapper>&,Pathfinding.Collections.UnsafeSpan1<Pathfinding.Graphs.Navmesh.TileHandler/Point64Wrapper>&,Pathfinding.Collections.UnsafeSpan1<Pathfinding.NavmeshCut/ContourBurst>&,Pathfinding.Collections.UnsafeSpan1<int>&,Pathfinding.Collections.UnsafeSpan1&,Unity.Collections.LowLevel.Unsafe.UnsafeList1<UnityEngine.Vector2Int>&,Unity.Collections.LowLevel.Unsafe.UnsafeList1&,int)
UnityEngine.<>c:b__0_0(Object, UnhandledExceptionEventArgs)

MAJOR ERROR 3 - Game continues to run but Pathfinding ‘sometimes’ breaks. Upon ending play mode, if Pathfinding has broke, unity freezes. If pathfinding did not break, unity will get stuck reloading domain the next time Play mode is launched.

Log

System.NullReferenceException: Object reference not set to an instance of an object
This Exception was thrown from a job compiled with Burst, which has limited exception support.
0x00007ff989a713ce (ntdll) KiUserExceptionDispatcher
0x00000271f0196188 (Mono JIT Code) Pathfinding.Clipper2Lib.ClipperBase:DoHorizontal (Pathfinding.Clipper2Lib.Active)
0x00000271f017c31b (Mono JIT Code) Pathfinding.Clipper2Lib.ClipperBase:ExecuteInternal (Pathfinding.Clipper2Lib.ClipType,Pathfinding.Clipper2Lib.FillRule)
0x00000271f015a823 (Mono JIT Code) Pathfinding.Clipper2Lib.Clipper64:Execute (Pathfinding.Clipper2Lib.ClipType,Pathfinding.Clipper2Lib.FillRule,System.Collections.Generic.List1<System.Collections.Generic.List1<Pathfinding.Clipper2Lib.Point64>>,System.Collections.Generic.List1<System.Collections.Generic.List1<Pathfinding.Clipper2Lib.Point64>>)
0x00000271f0156963 (Mono JIT Code) Pathfinding.Graphs.Navmesh.TileHandler:CutPolygon (Pathfinding.Collections.UnsafeSpan1<Pathfinding.Graphs.Navmesh.TileHandler/Point64Wrapper>&,Pathfinding.Collections.UnsafeSpan1<Pathfinding.Graphs.Navmesh.TileHandler/Point64Wrapper>&,Pathfinding.Collections.UnsafeSpan1<Pathfinding.NavmeshCut/ContourBurst>&,Pathfinding.Collections.UnsafeSpan1&,Pathfinding.Collections.UnsafeSpan1<int>&,Unity.Collections.LowLevel.Unsafe.UnsafeList1<UnityEngine.Vector2Int>&,Unity.Collections.LowLevel.Unsafe.UnsafeList1<int>&,int) (at ./Library/PackageCache/com.arongranberg.astar/Graphs/Navmesh/TileHandler.cs:953) 0x00000271f0151e3b (Mono JIT Code) (wrapper native-to-managed) Pathfinding.Graphs.Navmesh.TileHandler:CutPolygon (Pathfinding.Collections.UnsafeSpan1<Pathfinding.Graphs.Navmesh.TileHandler/Point64Wrapper>&,Pathfinding.Collections.UnsafeSpan1<Pathfinding.Graphs.Navmesh.TileHandler/Point64Wrapper>&,Pathfinding.Collections.UnsafeSpan1<Pathfinding.NavmeshCut/ContourBurst>&,Pathfinding.Collections.UnsafeSpan1<int>&,Pathfinding.Collections.UnsafeSpan1&,Unity.Collections.LowLevel.Unsafe.UnsafeList1<UnityEngine.Vector2Int>&,Unity.Collections.LowLevel.Unsafe.UnsafeList1&,int)
0x00007ff8d5ac3b77 (97dc418598cced24022449f7263d673) Pathfinding.Graphs.Navmesh.TileHandler.Pathfinding.Graphs.Navmesh.CutTiles_00000ADB$BurstDirectCall.Invoke (at C:/Users/brend/OneDrive/Documents/asteroid-rancher-2021/Library/PackageCache/com.unity.burst/.Runtime/unknown/unknown:0)
0x00007ff8d5aeee0b (97dc418598cced24022449f7263d673) Unity.Jobs.IJobExtensions.JobStruct`1<Pathfinding.Graphs.Navmesh.TileCutter.JobCutTiles>.Execute(ref Pathfinding.Graphs.Navmesh.TileCutter.JobCutTiles data, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref Unity.Jobs.LowLevel.Unsafe.JobRanges ranges, int jobIndex) → void_a8542dda2b3b28fb6a489532264bb448 from UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null (at C:/Users/brend/OneDrive/Documents/asteroid-rancher-2021/Library/PackageCache/com.unity.burst/.Runtime/unknown/unknown:0)
0x00007ff8d5aedcbd (97dc418598cced24022449f7263d673) 21a76e848d144b130c0976e4adfb32af
0x00007ff8dd2ab025 (Unity) ExecuteJob
0x00007ff8dd2ac13d (Unity) ForwardJobToManaged
0x00007ff8dd2a8339 (Unity) ujob_execute_job
0x00007ff8dd2a772f (Unity) lane_guts
0x00007ff8dd2aa374 (Unity) worker_thread_routine
0x00007ff8dd4a0a0d (Unity) Thread::RunThreadWrapper
0x00007ff989327374 (KERNEL32) BaseThreadInitThunk
0x00007ff989a1cc91 (ntdll) RtlUserThreadStart

After running into the errors repeatedly, I made a test project from scratch with all the default settings to see if I could replicate the issue. I’m pretty sure the root of the problem has to do with the interaction of the graph updates with the Navmesh Cut component, so I set up a ball with a NavmeshCut, then surrounded it with moving blocks with DynamicObstacles components.

As you can see in this video, we’re able to trigger one of the minor errors pretty much instantly, and a major error breaks the pathfinding completely several seconds later:

I’ve uploaded that test project here, so hopefully y’all should be able to replicate it as well!
AstarDebugDownload
(I’ve not tried sending a project via dropbox before so if that doesn’t work just let me know)

1 Like

Thanks for the thorough investigation. That made it really easy to find the issue.

Turns out there was a multithreading race condition when navmesh cutting was used and multiple graph updates were happening at the same time.

I’ll include a fix in the next update.

1 Like

That’s great to hear! Glad this was a relatively easy fix. Thanks for taking care of that so quickly.

Btw was just curious, do you have a rough idea of when that update with the fix will be available?
Currently planning a launch roadmap, and we’re hoping to fit an update to A* in there if it’s not too far off.

Within a few weeks at most.