Humanoid.Died not working

I’m having problems detecting when the player dies. I have this script inside a coroutine to detect when a player dies and do some other stuff too:

game:GetService('Players').PlayerAdded:Connect(function(player)
		player.CharacterAdded:Connect(function(character)
			character:WaitForChild("Humanoid").Died:Connect(function()
				print("".. player.Name .." died")
                -- some other stuff
			end)
		end)
end)

I tried this code on a separate script and it worked fine but when it’s inside the coroutine it doesn’t work. The rest of the coroutine runs but this part never works. Here is the full function used in the coroutine if you want to see it:

-- function that checks if everyone in the round is gone
function CheckPlayers(spwn, play)
	local PlayerService = game:GetService("Players")
	
	-- removes player from table if died (this part doesn't work)
	game:GetService('Players').PlayerAdded:Connect(function(player)
		player.CharacterAdded:Connect(function(character)
			character:WaitForChild("Humanoid").Died:Connect(function()
				print("".. player.Name .." died")
				if table.find(play, PlayerService:FindFirstChild(player.Name)) then
					local position = table.find(play, PlayerService:FindFirstChild(player.Name))
					table.remove(play, position)
				end
			end)
		end)
	end)
	
	-- remove player who touched the winbrick
	local deb = false
	spwn:WaitForChild("WinBrick").Touched:Connect(function(hit)
		if deb then return end
		if hit.Parent:FindFirstChild("Humanoid") then
			if table.find(play, PlayerService:FindFirstChild(hit.Parent.Name)) then
				deb = true
				local locate = table.find(play, PlayerService:FindFirstChild(hit.Parent.Name))
				table.remove(play, locate)
				task.wait(0.2)
				deb = false
			end
		elseif hit.Parent.Parent:FindFirstChild("Humanoid") then --sometimes handle of accessories touches the brick due to animation playing
			if table.find(play, PlayerService:FindFirstChild(hit.Parent.Parent.Name)) then
				deb = true
				local locate = table.find(play, PlayerService:FindFirstChild(hit.Parent.Parent.Name))
				table.remove(play, locate)
				task.wait(0.2)
				deb = false
			end
		end
	end)
	
	-- remove player from table if leave
	connection5 = game:GetService("Players").PlayerRemoving:Connect(function(player)
		print(player.Name .." has left the game")
		if table.find(play, PlayerService:FindFirstChild(player.Name)) then
			local position = table.find(play, PlayerService:FindFirstChild(player.Name))
			table.remove(play, position)
		end
		
	end)

	while task.wait(0.2) do
		if #play == 0 then
			print("Every single player has died or left the game")
			InRound = false
			break
		else
			print("One or more players are alive")
		end
		if Alive == false then
			print("Round Ended")
			connection5:Disconnect()
			break
		end
	end
end

It doesn’t even run the “print(”"… player.Name …" died")" when the player dies

game:GetService('Players').PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
local humanoid = character:FindFirstChild("Humanoid")
humanoid.Died:Connect(function()
end)
end)

That doesn’t work.
char limit

If you already have a player in the game when CheckPlayers is called then they will not be connected properly. You should separate your add player function and double-up it’s calls with existing players

local function add_player(player: Player)
	player.CharacterAdded:Connect(function(character)
		character:WaitForChild("Humanoid").Died:Connect(function()
			print("".. player.Name .." died")
			if table.find(play, PlayerService:FindFirstChild(player.Name)) then
				local position = table.find(play, PlayerService:FindFirstChild(player.Name))
				table.remove(play, position)
			end
		end)
	end)
end

function CheckPlayers(spwn, play)
	local PlayerService = game:GetService("Players")
	
	-- new players joining roblox will get called from this
	PlayerService.PlayerAdded:Connect(add_player)
	-- existing players in the game will get called from this
	for _, player in PlayerService:GetPlayers() do
		add_player(player)
	end
end

You should also track the RBXScriptConnections to not re-connect existing players, this can be done with a simple table of connections bound by player.

local already_added_players = {}

local function add_player(player: Player)
	-- player already connected! do not connect twice!
	if already_added_players[player] then
		return
	end

	already_added_players[player] = player.CharacterAdded:Connect(function(character)
		character:WaitForChild("Humanoid").Died:Connect(function()
			print("".. player.Name .." died")
			if table.find(play, PlayerService:FindFirstChild(player.Name)) then
				local position = table.find(play, PlayerService:FindFirstChild(player.Name))
				table.remove(play, position)
			end
		end)
	end)
end

local PlayerService = game:GetService("Players")
function CheckPlayers(spwn, play)
	-- new players joining roblox will get called from this
	PlayerService.PlayerAdded:Connect(add_player)
	-- existing players in the game will get called from this
	for _, player in PlayerService:GetPlayers() do
		add_player(player)
	end
end

PlayerService.PlayerRemoving:Connect(function(player)
	-- must remove players as the leave the game!
	already_added_players[player] = nil
end)

Maybe you can check when the humanoids health is changed (healthchanged) and is 0?
Or, you can check when the player dies like (humanoid.Died) when using the healthchanged method.

Worth noting that if your players already have a character when CheckPlayers runs then you will have to do the same function for existing characters and player.CharacterAdded connections.

Here is a script to detect when the player dies.

local Player = game.Players.LocalPlayer

repeat wait() until Player.Character

local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild('Humanoid')

Humanoid.HealthChanged:connect(function()
	if Humanoid then
		if Humanoid.Health < 1 then
			print(Player.Name .. ' is dead')
		end
	end
end)

Put this script into StarterCharacterScripts:

wait(.5)
local hum = script.Parent:WaitForChild("Humanoid")
hum:GetPropertyChangedSignal("Health"):Connect(function()
	if hum.Health == 0 then
		print("Dead")
	end
end)