AI creates new paths without finishing first

I’m in a gamejam, and my teammate made an AI script, but it wasn’t working so i started editing it and it got to a phase where it could wander but it wouldn’t generate a new path. So I started implementing that, but now the NPC will spam new paths if it gets as close to the goal as it can get (eg. house blocks it, gets close to the house, makes new path as it believes it’s “reached”)

i believe it has something to do with the boundary im using and placing models inside of that boundary.

Script
-- reorganized the script a little and added refined touches and comments breaking down wut happenz

-- SERVICES
local PathfindingService = game:GetService("PathfindingService")

-- INSTANCES
local npc = script.Parent
local boundary = game.Workspace.rr

-- IN-SCRIPT VARIABLES
local waitTime = 5

-- NPC-SPECIFIC VARIABLES
local humanoid = npc:FindFirstChild("Humanoid")
local rootPart = npc:FindFirstChild("HumanoidRootPart")


-- FUNCTIONS
local function DestroyWaypoints()

	for Table, Item in ipairs(workspace:GetChildren()) do
		if Item.Name == "WAYPOINT" and Item:IsA("BasePart") then
			print("destroying waypoint")
			Item:Destroy()
		end
	end
end


local function getRandomPointInArea()
	local minPos = boundary.Position - boundary.Size / 2
	local maxPos = boundary.Position + boundary.Size / 2

	local randomX = math.random(minPos.X, maxPos.X)
	local randomY = minPos.Y
	local randomZ = math.random(minPos.Z, maxPos.Z)

	return Vector3.new(randomX, randomY, randomZ)
end

local function wander()
		local goal = getRandomPointInArea() -- sets the path goal  to the return value of the random point
		print(getRandomPointInArea())
		local agentRadius = rootPart.Size.X / 2 -- sets radius to rootpart size/2
 		local agentHeight = rootPart.Size.Y -- height is set to rootpart y axis

		local path = PathfindingService:CreatePath({
			AgentRadius = agentRadius,
			AgentHeight = agentHeight,
		})
		
		path:ComputeAsync(rootPart.Position, goal)

		humanoid:MoveTo(goal)
		
	local wayPoints = path:GetWaypoints()
	if path.Status == Enum.PathStatus.Success then

		for _, waypoint in ipairs(wayPoints) do
			local visualizer = Instance.new("Part")
			visualizer.Color = Color3.fromRGB(184, 193, 17)
			visualizer.Material = Enum.Material.Neon
			visualizer.Anchored = true
			visualizer.Size = Vector3.new(.25, .25, .25)
			visualizer.Position = waypoint.Position
			visualizer.Parent = game.Workspace
			visualizer.Name = "WAYPOINT"
			visualizer.CanCollide = false
			visualizer.CanQuery = false
			
			
			
			if waypoint.Action == Enum.PathWaypointAction.Jump then
				DestroyWaypoints()
				wander()
			end

			humanoid:MoveTo(waypoint.Position)
			
			local OnFinish = humanoid.MoveToFinished:Connect(function(Reached)
				
				if Reached then
					DestroyWaypoints()
					print("reached")
					wander() -- generate new path

				end
				
			end)
			
			local timeOut = humanoid.MoveToFinished:Connect(function(reached)
					
				if not reached then
					warn("Stuck")
					DestroyWaypoints()
					humanoid.Jump = true
					wander() -- generate new path to goal
					
				elseif reached then
					DestroyWaypoints()
					task.wait(math.random(5, 10))
					print("reached")
					wander()
				end
			end)
		end
	else
		DestroyWaypoints()
		warn("PathFailed")
		wander()
	end
	
	end
	


wander()

here’s a video demonstrating the current state of the ai

I think the problem is the wander logic. You never disconnected OnFinish and timeOut, but when you call wander again, it create new OnFinish and timeOut connections. Also the script create a OnFinish and timeOut for each waypoint in the loop, in other words, if something’s wrong at any waypoint, wander will be called several times. And since the function is recursive, it will create more calls of wander, that create more connections and could trigger even more wander. MoveToFinished will fire false if the humanoid didn’t reach the destination in 8 seconds, potentially triggering something in your logic. Also you never gave time for the npc to reach the waypoint, humanoid:MoveToFinished:Wait() is needed in the loop, otherwise the npc will just go for the last one without going through others.

ah, i see! ill debug and edit after school and ill lyk what happens, thanks!