This works 50% of the time, then never works the second time

local shirtName = "Default"

game.ReplicatedStorage.clothesAndFootstepSoundAssigner.OnServerEvent:Connect(function(plr)
	print("fired")

	local char = plr.Character

	plr.CharacterAppearanceLoaded:Wait()

	--remove clothes
	for i, child in pairs(char:GetDescendants()) do
		print('doing thuis')
		if child:IsA("Shirt") or child:IsA("ShirtGraphic") or child:IsA("Pants") then
			child:Destroy()
		end



		--also, destroy any accessories that arent hair or hats
		if child:IsA("Accessory") then

			if child.AccessoryType ~= Enum.AccessoryType.Hat and child.AccessoryType ~= Enum.AccessoryType.Hair then
				child:Destroy()
			else
				--if it doesn't get destroyed, disable cantouch
				child.Handle.CanTouch = false
			end


		end
	end




	--add new ones
	print(shirtName)
	local shirt = game.ServerStorage:WaitForChild("shirts"):FindFirstChild(shirtName):Clone()
	shirt.Parent = char



end)

This works, like, 50% of the time? Sometimes it loads, other times it doesn’t.
Here’s the local script in starterplayerscripts for when to fire it:

game.Players.LocalPlayer.CharacterAdded:Connect(function()
	
	game.ReplicatedStorage.clothesAndFootstepSoundAssigner:FireServer()
	
end)

The goal is to be able to have customization be easier. I then have another remote event in the same server script listed at the top of the post-

game.ReplicatedStorage.changeShirt.OnServerEvent:Connect(function(name)
	
	shirtName = name
	
end)

This way, when I fire the remote event on the client (for example, when they click a button to change shirts) it changes the value of “shirtName” on the server, meaning the next time the character is added, the remote event fires, and adds the NEW shirt that matches “shirtName”, meaning that it worked. Instead, spawning in doesn’t even give you the default shirt half the time (no idea why it seems to work at random) and ALWAYS gives me the error “attempt to index nil with :Clone()” when I respawn (have my character added, triggering the remote event) after firing (locally) the remote event to change my shirt.

Why does this not work correctly?

NOTE:
After some debugging, I discovered when it doesn’t work (the first time, at least) it never seems to get past this line:

plr.CharacterAppearanceLoaded:Wait()

Why?

Maybe, it doesn’t get past this line for 1 of 2 reasons:
-The appearance already loaded and the event already fired before the script loaded/got to that part.
or
-There was an issue with loading the appearance, which is probably not the case.

how should i fix this then?

Add the CharacterAppearanceLoaded:Wait() here, before firing the function?

Or maybe replace the CharacterAppearanceLoaded:Wait() with

local loaded = plr:HasAppearanceLoaded()
if loaded then
else
plr.CharacterAppearanceLoaded:Wait()
end

Edit: HasAppearanceLoaded, not HasCharacterLoaded

The second option will probably fix the issue

good news, bad news
Good news: this seemed to fix the problem of it only working half the time completely
Bad news: The second time, after changing the shirtName, there’s still the issue of “attempt to index nil with “Clone()””

nvm turns out i just forgot an extremely basic principle of remote events lmao we good

I think the problem may be because of this:

As in a OnServerEvent, the arguments are: player client that fired the event to the server, and the rest of the arguments

The issue is probably that it is trying to change the shirtName to an instance, causing an error.

Try printing the name argument to see what it prints out.

ok new new new problem
so

local char = plr.Character
	
	--checking if character has loaded
	local loaded = plr:HasAppearanceLoaded()
	
	if loaded then
	else
		plr.CharacterAppearanceLoaded:Wait()
	end

	--remove clothes
	for i, child in pairs(char:GetDescendants()) do
		print("doing this")
		if child:IsA("Shirt") or child:IsA("ShirtGraphic") or child:IsA("Pants") then
			child:Destroy()
		end



		--also, destroy any accessories that arent hair or hats
		if child:IsA("Accessory") then

			if child.AccessoryType ~= Enum.AccessoryType.Hat and child.AccessoryType ~= Enum.AccessoryType.Hair then
				child:Destroy()
			else
				--if it doesn't get destroyed, disable cantouch
				child.Handle.CanTouch = false
			end


		end
	end

The point of this is to remove all accessories when the player’s character is added
However, when I use “getdescendants”, sometimes (i find evidence of this in the print statements) the character isn’t finished loading, and I don’t get all the descendants, meaning it fails to destroy accessories
So, I use the system at the top to wait until the character has completely loaded before getting descendants
I have just learned this seems to no longer work?

It occurs to me that since I’m searching for accessories and clothing, I don’t need to get descendants, only the children, meaning that it shouldn’t take as long to work, and be fine
But because of the problem with get descendants that means this method could be inconsistent under certain conditions

Do you have any ideas on how to fix it?

EDIT: getchildren does not fix anything. It still doesn’t work.

I thought of a possible fix for this issue, but i don’t know if it would be very optimized.

Basically, you make it so it does this:

Everytime a child is added to the player character (also it can be :GetChildren() instead of :GetDescendants)