Attachment is not being created for some players

I have an overhead inventory UI that needs to be added to the player’s head every time they join. It breaks on most accounts, such as my sister’s account and my alt, but it works perfectly on my main account.

Here’s my script:

local gui = script.BillboardGui

...

local function addGui(char)
	local head = char:WaitForChild("Head")
	local attachment = Instance.new("Attachment")
	local newGui = gui:Clone()
	attachment.Parent = head
	attachment.Name = "InventoryAttachment"
	attachment.Position = Vector3.new(0, 2, 0)
	newGui.Parent = attachment
end

...

game.Players.PlayerAdded:Connect(function(plr)
	plr.CharacterAdded:Connect(addGui)
end)

...
Full script
local gui = script.BillboardGui
local event = game.ReplicatedStorage.Events.Inventory
local clientEvent = game.ReplicatedStorage.Events.InventoryClient

local function addGui(char)
	local head = char:WaitForChild("Head")
	local attachment = Instance.new("Attachment")
	local newGui = gui:Clone()
	attachment.Parent = head
	attachment.Name = "InventoryAttachment"
	attachment.Position = Vector3.new(0, 2, 0)
	newGui.Parent = attachment
end

local function add(plr, item)
	local char = plr.Character
	if not char then return end
	local head = char:WaitForChild("Head")
	local attachment = head:WaitForChild("InventoryAttachment")
	local gui = attachment:WaitForChild("BillboardGui")
	
	if gui.Enabled then
		warn("Replacing " .. gui.TextLabel.Text .. " with " .. item)
	end
	
	gui.Enabled = true
	gui.TextLabel.Text = "<font size=\"8\">Holding:</font>\n<b>" .. item .. "</b>"
	
	return
end

local function remove(plr)
	local char = plr.Character
	if not char then return end
	local head = char:WaitForChild("Head")
	local attachment = head:WaitForChild("InventoryAttachment")
	local gui = attachment:WaitForChild("BillboardGui")

	gui.Enabled = false
	
	return
end

local function check(plr)
	local char = plr.Character
	if not char then return end
	local head = char:WaitForChild("Head")
	local attachment = head:WaitForChild("InventoryAttachment")
	local gui = attachment:WaitForChild("BillboardGui")
	
	if gui.Enabled then
		return string.sub(gui.TextLabel.Text, 35, string.len(gui.TextLabel.Text) - 4)
	end
end

local function onInvoke(plr, mode, item)
	if mode == "Add" then
		add(plr, item)
	elseif mode == "Remove" then
		remove(plr)
	elseif mode == "Check" then
		return check(plr)
	else
		warn("Invalid inventory mode!")
	end
end

game.Players.PlayerAdded:Connect(function(plr)
	plr.CharacterAdded:Connect(addGui)
end)

event.OnInvoke = onInvoke
clientEvent.OnServerInvoke = onInvoke

Images

Alt (bugged):

Main (expected):

Output was empty, so I didn’t include it here.

Fast responses are appreciated but any will be helpful. I gotta put this game back up soon!

try this and read the output

local gui = script.BillboardGui
local event = game.ReplicatedStorage.Events.Inventory
local clientEvent = game.ReplicatedStorage.Events.InventoryClient

local function addGui(char)
    local head = char:WaitForChild("Head", 10) -- Wait up to 10 seconds for the Head
    if not head then
        warn("Failed to find Head for character: " .. char.Name)
        return
    end

    -- Clean up existing attachments
    local oldAttachment = head:FindFirstChild("InventoryAttachment")
    if oldAttachment then
        oldAttachment:Destroy()
    end

    local attachment = Instance.new("Attachment")
    local newGui = gui:Clone()
    attachment.Parent = head
    attachment.Name = "InventoryAttachment"
    attachment.Position = Vector3.new(0, 2, 0)
    newGui.Parent = attachment
end

local function add(plr, item)
    local char = plr.Character
    if not char then return end
    local head = char:WaitForChild("Head")
    local attachment = head:WaitForChild("InventoryAttachment")
    local gui = attachment:WaitForChild("BillboardGui")

    if gui.Enabled then
        warn("Replacing " .. gui.TextLabel.Text .. " with " .. item)
    end

    gui.Enabled = true
    gui.TextLabel.Text = "<font size=\"8\">Holding:</font>\n<b>" .. item .. "</b>"
end

local function remove(plr)
    local char = plr.Character
    if not char then return end
    local head = char:WaitForChild("Head")
    local attachment = head:WaitForChild("InventoryAttachment")
    local gui = attachment:WaitForChild("BillboardGui")

    gui.Enabled = false
end

local function check(plr)
    local char = plr.Character
    if not char then return end
    local head = char:WaitForChild("Head")
    local attachment = head:WaitForChild("InventoryAttachment")
    local gui = attachment:WaitForChild("BillboardGui")

    if gui.Enabled then
        return string.sub(gui.TextLabel.Text, 35, string.len(gui.TextLabel.Text) - 4)
    end
end

local function onInvoke(plr, mode, item)
    if mode == "Add" then
        add(plr, item)
    elseif mode == "Remove" then
        remove(plr)
    elseif mode == "Check" then
        return check(plr)
    else
        warn("Invalid inventory mode!")
    end
end

game.Players.PlayerAdded:Connect(function(plr)
    plr.CharacterAdded:Connect(addGui)
end)

event.OnInvoke = onInvoke
clientEvent.OnServerInvoke = onInvoke

Output and results are the same as before, so it seems like the problem is in this section:

local attachment = Instance.new("Attachment")
local newGui = gui:Clone()
attachment.Parent = head
attachment.Name = "InventoryAttachment"
attachment.Position = Vector3.new(0, 2, 0)
newGui.Parent = attachment

I added some prints in these spots:

    local attachment = Instance.new("Attachment")
	print(attachment)
	local newGui = gui:Clone()
	print(newGui)
	attachment.Parent = head
	attachment.Name = "InventoryAttachment"
	attachment.Position = Vector3.new(0, 2, 0)
	newGui.Parent = attachment
	print(newGui:GetFullName())

And this is the result (alt account):

Screenshot 2024-12-20 at 11.49.13 AM

Screenshot 2024-12-20 at 11.49.52 AM

So it’s there, but it’s… not. Might be getting destroyed somewhere.