Characteradded only working 50% of the time on launch

so i have a script that puts a GUI on the players screen of a cooldown and a system that launches the player forward, it all works but when i launch the game most of the time characteradded does not fire until i reset, whats wrong with my code? (local script in starterplayer)

-- dogo 7/13
local localPlayer = game.Players.LocalPlayer
local fartReplicator = game.ReplicatedStorage:WaitForChild("FartReplicator")
local ragdollReplicator = game.ReplicatedStorage:WaitForChild("RagdollReplicator")
local MarketplaceService = game:GetService("MarketplaceService")
local UserInputService = game:GetService("UserInputService")

local cooldown
if MarketplaceService:UserOwnsGamePassAsync(localPlayer.UserId, 851639456) then
	cooldown = 0.8
else
	cooldown = 1.0
end

local function ragdollCharacter(character, amountOfTimeRagdolled)
	if not character then return end

	local humanoid = character:FindFirstChildOfClass("Humanoid")
	if not humanoid then return end

	local rootPart = character:FindFirstChild("HumanoidRootPart")
	if not rootPart then return end

	local constraints = {}
	local motors = {}

	-- Helper function to create BallSocketConstraints with more extreme limits
	local function createBallSocketConstraint(part0, part1, attachment0, attachment1)
		local constraint = Instance.new("BallSocketConstraint")
		constraint.Attachment0 = attachment0
		constraint.Attachment1 = attachment1
		constraint.LimitsEnabled = true
		constraint.TwistLimitsEnabled = true
		constraint.UpperAngle = 90
		constraint.TwistUpperAngle = 90
		constraint.TwistLowerAngle = -90
		constraint.Parent = part0
		table.insert(constraints, constraint)
	end

	-- Disable the humanoid's state
	humanoid.PlatformStand = true

	-- Iterate through each part of the character
	for _, part in ipairs(character:GetDescendants()) do
		if part:IsA("Motor6D") then
			table.insert(motors, part)

			local attachment0 = Instance.new("Attachment")
			attachment0.Name = "RagdollAttachment0"
			attachment0.CFrame = part.C0
			attachment0.Parent = part.Part0

			local attachment1 = Instance.new("Attachment")
			attachment1.Name = "RagdollAttachment1"
			attachment1.CFrame = part.C1
			attachment1.Parent = part.Part1

			createBallSocketConstraint(part.Part0, part.Part1, attachment0, attachment1)
			part.Enabled = false

		elseif part:IsA("BasePart") and part.Name ~= "HumanoidRootPart" then
			-- Apply random torque to the parts
			local bodyAngularVelocity = Instance.new("BodyAngularVelocity")
			bodyAngularVelocity.AngularVelocity = Vector3.new(
				math.random(-10, 10),
				math.random(-10, 10),
				math.random(-10, 10)
			)
			bodyAngularVelocity.MaxTorque = Vector3.new(4000, 4000, 4000)
			bodyAngularVelocity.Parent = part
			table.insert(constraints, bodyAngularVelocity)
		end
	end

	-- Wait for the specified ragdoll time
	task.wait(amountOfTimeRagdolled)

	-- Restore the original Motor6Ds and remove constraints
	for _, motor in ipairs(motors) do
		motor.Enabled = true
	end

	for _, constraint in ipairs(constraints) do
		constraint:Destroy()
	end

	for _, part in ipairs(character:GetDescendants()) do
		if part:IsA("Attachment") and (part.Name == "RagdollAttachment0" or part.Name == "RagdollAttachment1") then
			part:Destroy()
		end
	end

	-- Ensure the humanoid stands straight up and faces the same direction
	local rootPart = character:FindFirstChild("HumanoidRootPart")
	if rootPart then
		rootPart.CFrame = CFrame.new(rootPart.Position) * CFrame.Angles(0, 0, 0)
	end
	humanoid.PlatformStand = false
end

local function characterAdded(character)
	local cooldownGUI = script:WaitForChild("CooldownUI"):Clone()
	cooldownGUI.Parent = localPlayer.PlayerGui
	local debounce = true
	local humanoidRootPart = character:WaitForChild("HumanoidRootPart")
	local isSpaceHeld = false
	cooldownGUI.TextLabel.Text = "Cooldown: " .. cooldown

	local function handleInputBegan(input, gameProcessedEvent)
		if input.UserInputType == Enum.UserInputType.Touch or input.KeyCode == Enum.KeyCode.Space then
			isSpaceHeld = true
			wait(0.25)
			if isSpaceHeld and debounce then
				fartReplicator:FireServer()
				debounce = false
				task.spawn(function()
					local initialTime = cooldown
					local decrement = 0.1
					for i = cooldown, 0, -decrement do
						wait(decrement)
						initialTime = initialTime - decrement
						if initialTime < 0 then
							initialTime = cooldown
						end
						if cooldownGUI:FindFirstChild("TextLabel") then
							if initialTime == cooldown then
								cooldownGUI:FindFirstChild("TextLabel").BackgroundColor3 = Color3.new(0, 1, 0)
							else
								cooldownGUI:FindFirstChild("TextLabel").BackgroundColor3 = Color3.new(1, 0, 0)
							end
							cooldownGUI:FindFirstChild("TextLabel").Text = "Cooldown: " .. string.format("%.1f", initialTime)
						end
					end
				end)
				local forwardDirection = humanoidRootPart.CFrame.LookVector
				local upwardDirection = Vector3.new(0, 1, 0)

				local forwardStrength = 825 / 1.5
				local upwardStrength = 450 / 1.5

				local impulse = (forwardDirection * forwardStrength) + (upwardDirection * upwardStrength)
				humanoidRootPart:ApplyImpulse(impulse)
				ragdollCharacter(localPlayer.Character, 0.45)
				wait(cooldown)
				debounce = true
			end
		end
	end

	local function handleInputEnded(input, gameProcessedEvent)
		if input.UserInputType == Enum.UserInputType.Touch or input.KeyCode == Enum.KeyCode.Space then
			isSpaceHeld = false
		end
	end

	UserInputService.InputBegan:Connect(handleInputBegan)
	UserInputService.InputEnded:Connect(handleInputEnded)

	if not localPlayer.PlayerGui:FindFirstChild("CooldownUI") then
		print("cooldownGUI not detected")
		characterAdded(character)
	end
end

localPlayer.CharacterAdded:Connect(characterAdded)

Why don’t you just use CharacterAppearanceLoaded?
Player | Documentation - Roblox Creator Hub

CharacterAdded can be inconsistent because it only fires when well, a new character is added. The local script doesn’t really recognize as local script is loaded around the same time your character is. So, it can only work if the local script loads faster than your character loads, which cause inconsistency.

its still showing issues, i dont think this is a reliable solution either as it can still fail.

What’s probably happening is that sometimes the character loads before the script can connect to the event. Solution is to run your character added function if there is already a character.

Why don’t you add repeat task.wait() until game:IsLoaded() at the top of your script?

I just thought of that,

repeat wait() until localPlayer.Character

Thanks though!

That could work too. However, it always good to yield local scripts until the game has loaded. Has the problem been solved?

I’m a bit late but use this reference for when you’re connecting to CharacterAdded / PlayerAdded:
CharacterAdded functions not loading correctly - Help and Feedback / Scripting Support - Developer Forum | Roblox