Problem with my ability activation

My ability activation is repeating twice whenever I unequip the weapon after I activate it and then I equip it again. I suppose it is linked to a problem with my activation system so please help with this problem.

Video showcasing the problem (see output):

Client Script:

local Players = game:GetService("Players")

local player = Players.LocalPlayer
local Backpack = player.Backpack
local gui = player.PlayerGui:WaitForChild("CharacterGui")

-- Function to handle the removal of weapons
local function handleWeaponDeletion()
	-- Clear the ability buttons when a weapon is removed
	for _, button in pairs(gui.Abilities:GetChildren()) do
		if button:IsA("UIListLayout") or button.Name == "Template" then
			continue
		end
		button:Destroy()
	end
	gui.Abilities.Visible = false
	gui.ManageTools.Visible = false -- Reset ManageTools UI when the weapon is unequipped
end

local function handleWeaponRemoval()
	gui.Abilities.Visible = false
	gui.ManageTools.Visible = false -- Reset ManageTools UI when the weapon is unequipped
	return
end

-- Function to handle the addition of weapons
local function handleWeaponAddition(weapon)
	gui.Abilities.Visible = true

	for _, attack in ipairs(weapon.Abilities:GetChildren()) do
		local attackConfig = attack:GetAttributes()
		local button = gui.Abilities:FindFirstChild(attack.Name)

		-- Create a new button if it doesn't exist
		if not button then
			button = gui.Abilities.Template:Clone()
			button.Name = attack.Name
			button.Image = attack.Image.Texture
			button.Ability.Text = attack.Name
			button.Visible = true
			button.Parent = gui.Abilities
		end

		-- Function to run when the ability button is activated
		local function onButtonActivated()
			print("eeeeee") -- Important for testing (SEE VIDEO)
			-- Prevent multiple activations
			if button.Active == false then
				return
			end

			-- Handle ability cooldowns
			local function handleCooldown(ability, cooldownDuration)
				if cooldownDuration > 0 then
					ability.Shadow.Cooldown.Visible = true
					ability.GuiCooldown.Value = cooldownDuration

					for remainingTime = cooldownDuration, 0, -0.1 do
						ability.GuiCooldown.Value = remainingTime
						ability.Shadow.Cooldown.Text = string.format("%.1f", remainingTime)
						task.wait(0.1)

						if ability.GuiCooldown.Value ~= remainingTime then
							return
						end
					end
				end

				ability.Active = true
				ability.Shadow.Visible = false
			end

			-- Process each ability button
			for _, ability in pairs(button.Parent:GetChildren()) do
				if not ability:IsA("ImageButton") then
					continue
				end

				ability.Active = false
				ability.Shadow.Visible = true

				local holdCooldown = attack:GetAttribute("HoldCooldown")
				if not holdCooldown then
					coroutine.wrap(handleCooldown)(ability, attackConfig["Cooldown"])
				else
					ability.Shadow.Cooldown.Visible = false
					coroutine.wrap(function()
						local result = MouseRaycast(sentryToSpawn)
						while not result or not result.Instance or not workspace.Maps:IsAncestorOf(result.Instance) do
							result = MouseRaycast(sentryToSpawn)
							RunService.RenderStepped:Wait()
						end

						if ability == button then
							AddPlaceholderSentry(attack)
						end

						-- Wait for the hold cooldown to change
						attack:GetAttributeChangedSignal("HoldCooldown"):Wait()
						handleCooldown(ability, attackConfig["Cooldown"])
					end)()
				end
			end

			-- Fire the server event to activate the ability
			ActivateAbility:FireServer(attack, weapon)
		end

		button.Activated:Connect(onButtonActivated)
	end
end

-- Main function that runs when the player's weapon changes its parent
local function AncestryChanged(weapon)
	warn("a")
	
	if not weapon then
		handleWeaponDeletion()
		return
	end

	local weaponEquipped = Players:GetPlayerFromCharacter(weapon.Parent)
	if not weaponEquipped or not weapon:FindFirstChild("Abilities") then
		handleWeaponRemoval() -- problem cuz GuiCooldown relies on this
		return
	end

	handleWeaponAddition(weapon)
end

-- Connect the functions to the appropriate events
Backpack.ChildAdded:Connect(AncestryChanged)
Backpack.ChildRemoved:Connect(AncestryChanged)
player.Character.ChildRemoved:Connect(AncestryChanged)

Please comment if you can help and if any more context is required, do message me. Thank you

The problem the script attaches Activate Event to a function every time it the tool get equip
that means the code button.Activated:Connect(onButtonActivated) will run every time it the tool get equip

for example if you equip / unequip the tool 5 times when you activate the tool it will print “eeee” 5 times because it attach the function 5 times

you can fix this by using connections
you can find some example of using it here: What are connections, and how do they work?

I’ll check that out in a bit.

adding letters