This is a horrible solution; there is no guarantee that the head or face will be present, even after wait(). If there truly was a delay, you should be using :WaitForChild(childName: string) like so:
local head = chr:WaitForChild("Head");
local face = head:WaitForChild("Face");
face:Destroy();
It works for me in a server script so all that I can assume is that it’s in a LocalScript. PlayerAdded will NOT return the localplayer on the client, because the script only runs when the player is loaded in. Try using this localscript instead, in StarterGui:
local player = game:GetService('Players').LocalPlayer
player.Character:WaitForChild('Head').face:Destroy()
This also will not replicate, you need to do this in a server script to make it show on the server. The script you already provided us with should work, on the server.
edit: I actually found a solution while scrolling through the roblox devforum
game.Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
local head = character:WaitForChild("Head")
repeat wait() until head ~= nil
repeat wait() until head:FindFirstChildWhichIsA("Decal") ~= nil
head:FindFirstChildWhichIsA("Decal"):Destroy()
end)
end)