Path:ComputeAsync() is sucessful, but doesn't return waypoints when called frequently

local Debris = game:GetService("Debris")
local PathfindingService = game:GetService("PathfindingService")
local RunService = game:GetService("RunService")


local model = script.Parent :: Model
local humanoid = model:FindFirstChildOfClass("Humanoid") :: Humanoid

local target = model.Configuration.Target.Value

local path: Path = PathfindingService:CreatePath()

local waypoints = {}
local currentWaypointIndex


local function VisualizeWaypoints(waypoints)
	workspace.Waypoints:ClearAllChildren()
	for _, waypoint in waypoints do
		local part = Instance.new("Part")
		part.Size = Vector3.new(1, 1, 1)
		part.Shape = Enum.PartType.Ball
		part.Material = Enum.Material.SmoothPlastic
		part.CanCollide = false
		part.Anchored = true
		part.Position = waypoint.Position
		part.Color = if waypoint.Action == Enum.PathWaypointAction.Jump then Color3.fromRGB(0, 255, 0) else Color3.fromRGB(255, 255, 255)
		part.Parent = workspace.Waypoints
	end
end


local function _computeAsync(targetPosition: Vector3)
	path:ComputeAsync(model.PrimaryPart.Position, targetPosition)
end


local function _moveTo(targetPosition: Vector3)
	if waypoints[currentWaypointIndex].Action == Enum.PathWaypointAction.Jump then
		humanoid.Jump = true
	end
	humanoid:MoveTo(waypoints[currentWaypointIndex].Position)
end


local function RunAI()
	
	_computeAsync(target.Position)
	
	if path.Status == Enum.PathStatus.Success then
		waypoints = path:GetWaypoints()
		VisualizeWaypoints(waypoints)
	end
	
	if #waypoints > 0 then
		currentWaypointIndex = 2
		_moveTo(waypoints[currentWaypointIndex].Position)
	else
		print('no waypoints???')
		humanoid:MoveTo(target.Position)
	end
	
end


local function MoveToFinished(reached)
	if reached and currentWaypointIndex < #waypoints then
		currentWaypointIndex += 1
		_moveTo(waypoints[currentWaypointIndex].Position)
	end
end


local function OnPathBlocked(blockedWaypointIndex)
	if blockedWaypointIndex >= currentWaypointIndex then
		RunAI()
	end
end


local function OnTargetPositionChanged()
	RunAI()
end


local moveToFinishedConnection: RBXScriptConnection = humanoid.MoveToFinished:Connect(MoveToFinished)
local onTargetPositionChangedConnection: RBXScriptConnection = target:GetPropertyChangedSignal("Position"):Connect(OnTargetPositionChanged)
local pathBlockedConnection: RBXScriptConnection = path.Blocked:Connect(OnPathBlocked)


humanoid.Died:Connect(function()
	moveToFinishedConnection:Disconnect()
	onTargetPositionChangedConnection:Disconnect()
	pathBlockedConnection:Disconnect()
	path:Destroy()
	Debris:AddItem(model, 8)
end)


RunAI()

this runs in a serverscript
lines 55-60 are where the problem occurs

line 60 is where i added a cludge where the humanoid moves straight to the target, as the character would stutter otherwise

Calculating the path requires a fair bit of computing. This computing requirement is what causes the slight delays. When you move the part and expect it to recalculate before it is finished calculating the current one, it stops calculating the old one and calculates the new oneā€¦ repeatedly

surely a successful path and its waypoints are mutually exclusive right?

if a successful path can return 0 waypoints, that ought to be documented wouldnt it?