Client pathfinding interrupts other NPCs?

Hey! I’m having some pathfinding issues. I currently have NPC classes on the client that handle their own pathfinding. However, it appears that the paths get interrupted and mixed up?

I’m not sure if this is a caveat with pathfinding behavior I’m unaware of, or if it’s just a code issue. One thing to note, this is done in response to remote events but I’ve checked and remote events are not being handled by all NPCs at once, so it’s not a networking issue.

It appears they all go to where the first NPC is going. When the first NPC teleports to the second floor, the NPCs on the bottom go to the same place the top NPC is going with different y values.

Client NPC class (relevant functions only)

function NPCSuperClient.new(serviceBag, id, appearance)
    local self = setmetatable(BaseObject.new(game.ReplicatedStorage.NPC:Clone()), NPCSuperClient)

    self._serviceBag = serviceBag

    self.id = id
    self.appearance = appearance

    self.humanoid = self._obj.Humanoid
    self.character = self._obj

    self._interactionService = serviceBag:GetService(InteractionServiceClient)

    PromiseGetRemoteEvent("NPC_Action"):Then(function(event)
        self._npcAction = event
    end)

    PromiseGetRemoteEvent("NPCMoveToFinished"):Then(function(event)
        self._npcMoveToFinished = event
    end)

    PromiseGetRemoteEvent("NPCInteracted"):Then(function(event)
        self._npcInteracted = event
    end)

    self:Enable()

    return self
end

function NPCSuperClient:Enable()
    self.character.UpperTorso.CanCollide = false

    self._npcAction.OnClientEvent:Connect(function(action, id, ...)
        if self.id ~= id then return end

        if self[action] then
            self[action](self, ...)
        end
    end)
end

function NPCSuperClient:MoveTo(position)
    --@TODO; fire move to finished when done
    self._currentPath = PathfindingService:CreatePath({
        AgentRadius = 3,
        AgentHeight = 6,
        AgentCanJump = false,
    })

    local success, errorMessage = pcall(function()
		self._currentPath:ComputeAsync(self.character.PrimaryPart.Position, position)
	end)
 
	if success and self._currentPath.Status == Enum.PathStatus.Success then
		-- Get the path waypoints
		local waypoints = self._currentPath:GetWaypoints()
        local blockedConnection

		-- Detect if path becomes blocked
		blockedConnection = self._currentPath.Blocked:Connect(function(blockedWaypointIndex)
			-- Check if the obstacle is further down the path
			if blockedWaypointIndex >= nextWaypointIndex then
				-- Stop detecting path blockage until path is re-computed
				blockedConnection:Disconnect()
				-- Call function to re-compute new path
				self:MoveTo(position)
			end
		end)
 
		-- Detect when movement to next waypoint is complete
        local reachedConnection

		if not reachedConnection then
			reachedConnection = self.humanoid.MoveToFinished:Connect(function(reached)
				if reached and nextWaypointIndex < #waypoints then
					-- Increase waypoint index and move to next waypoint
					nextWaypointIndex += 1
					self.humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
				else
					reachedConnection:Disconnect()
					blockedConnection:Disconnect()

                    -- Pathfinding is complete!
                    self._npcMoveToFinished:FireServer(self.id, position)
				end
			end)
		end
 
		-- Initially move to second waypoint (first waypoint is path start; skip it)
		nextWaypointIndex = 2
		self.humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
	else
		warn("Path not computed!", errorMessage)
	end
end

Obscure behavior:
4f3a38b25d20016c360115157b9d0afc

Let me know if you need to see more code or have any questions!