Handcuff loop not ending?

I am currently trying to make an advanced handcuff script, and when the player is detained they are forced to follow the detainer. That works until the player is released and they are still forced to follow the detainer. Why is this?

local cuffEvent = Instance.new("RemoteEvent", game.ReplicatedStorage)
cuffEvent.Name = "CuffPlayer"

local uncuffEvent = Instance.new("RemoteEvent", game.ReplicatedStorage)
uncuffEvent.Name = "UncuffPlayer"

local detainEvent = Instance.new("RemoteEvent", game.ReplicatedStorage)
detainEvent.Name = "DetainPlayer"

local releaseEvent = Instance.new("RemoteEvent", game.ReplicatedStorage)
releaseEvent.Name = "ReleasePlayer"

local function onCuffPlayer(player, targetCharacter)
	local cuffedValue = Instance.new("BoolValue")
	cuffedValue.Name = "Cuffed"
	cuffedValue.Parent = targetCharacter
	local player2 = game.Players:GetPlayerFromCharacter(targetCharacter)
	cuffEvent:FireClient(player2)
	local humanoid = targetCharacter:WaitForChild("Humanoid")
	humanoid:UnequipTools()
end

local function onUncuffPlayer(player, targetCharacter)
	local cuffedValue = targetCharacter:FindFirstChild("Cuffed")
	if cuffedValue then
		cuffedValue:Destroy()
	end
	local detainedValue = targetCharacter:FindFirstChild("Detained")
	if detainedValue then
		detainedValue:Destroy()
	end
	local player2 = game.Players:GetPlayerFromCharacter(targetCharacter)
	uncuffEvent:FireClient(player2)
end

local function onDetainPlayer(player, targetCharacter)
	local detainedValue = Instance.new("BoolValue")
	detainedValue.Name = "Detained"
	detainedValue.Parent = targetCharacter
	local player2 = game.Players:GetPlayerFromCharacter(targetCharacter)
	detainEvent:FireClient(player2)
	local humanoid = targetCharacter:WaitForChild("Humanoid")
	local detainer = player.Character or player.CharacterAddded:Wait()
	local root = detainer:WaitForChild("HumanoidRootPart")
	while detainedValue do
		task.wait()
		humanoid:MoveTo(root.Position + root.CFrame.LookVector * 4);
	end
end

local function onReleasePlayer(player, targetCharacter)
	local detainedValue = targetCharacter:FindFirstChild("Detained")
	if detainedValue then
		detainedValue:Destroy()
	end
	local player2 = game.Players:GetPlayerFromCharacter(targetCharacter)
	releaseEvent:FireClient(player2)
end

cuffEvent.OnServerEvent:Connect(onCuffPlayer)
uncuffEvent.OnServerEvent:Connect(onUncuffPlayer)
detainEvent.OnServerEvent:Connect(onDetainPlayer)
releaseEvent.OnServerEvent:Connect(onReleasePlayer)

This is likely due to the infinite loop in the onDetainPlayer function. The while detainedValue do loop continues running indefinitely, even after the Detained value is destroyed.

You need to add a condition to break out of the loop when the Detained value is no longer present. One way to achieve this is to use a connection to the AncestryChanged event of the detainedValue and disconnect it when the value is destroyed.

local function onDetainPlayer(player, targetCharacter)
    local detainedValue = Instance.new("BoolValue")
    detainedValue.Name = "Detained"
    detainedValue.Parent = targetCharacter
    local player2 = game.Players:GetPlayerFromCharacter(targetCharacter)
    detainEvent:FireClient(player2)
    local humanoid = targetCharacter:WaitForChild("Humanoid")
    local detainer = player.Character or player.CharacterAdded:Wait()
    local root = detainer:WaitForChild("HumanoidRootPart")
    
    local function onAncestryChanged()
        if not detainedValue:IsDescendantOf(game) then
            humanoid:MoveTo(nil)
            task.wait()
            break
        end
    end

    detainedValue.AncestryChanged:Connect(onAncestryChanged)

    while detainedValue and detainedValue:IsDescendantOf(game) do
        task.wait()
        humanoid:MoveTo(root.Position + root.CFrame.LookVector * 4)
    end
end