Runservice Heartbeat stopped for no reason at random times

  1. What do you want to achieve? Keep it simple and clear!
    I want this module run perfectly since it handle all ai, some damage module, some hitbox, some tools, some stored attacks without it breaking for no reason at random times, also theres no error output so i still can’t solve it
  2. What is the issue? Include screenshots / videos if possible!
    The issue is as the title says, Runservice Heartbeat stopped for no reason at random times, Some AI just stand there when the service breaking for no reason and other attack inside it. You can see the code below. No screenshots or videos because theres no error output causing this, it only send the output if ActiveConnection already exist, which causing the stored stuff to stack and never run
  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I tried printing method on the heartbeat to see how far it running and where it stop incase it break, but its useless when it break for no reason it just did one single iteration/frame fired/loop and stopped, I tried looking solutions on Dev Hub but theres no solved case and few of them only having this issue

It worked fine on studio and never break, but in game it just break at random time
Some attack tools cooldown handling, storing attacks, hitbox detection, damage module and all enemy AI fire this function below every time they are added to workspace

function CharStuffs:CheckConnection()
	if ActiveConnection then 
		warn(ActiveConnection, "there already connection, Active attacks: " .. #ActiveAttacks .. ", Active CDs: " .. CountActiveCDs() .. ", Active Stored Attacks: " .. #StoreAttacks .. ", Active Store Loop DMG Modules: " .. #StoreLoopDMGAttacks .. ", Active NPC Tracking: " .. #StoreNPCTracking) 
		return
	end
	
	if not ActiveConnection then
		ActiveConnection = RS.Heartbeat:Connect(function(t)
			--print(ActiveConnection, t .. ", running the module loop, Active attacks: " .. #ActiveAttacks .. ", Active CDs: " .. CountActiveCDs() .. ", Active Stored Attacks: " .. #StoreAttacks .. ", Active Store Loop DMG Modules: " .. #StoreLoopDMGAttacks .. ", Active NPC Tracking: " .. #StoreNPCTracking)
			if #ActiveAttacks <= 0 and CountActiveCDs() <= 0 and #StoreAttacks <= 0 and #StoreLoopDMGAttacks <= 0 and #StoreNPCTracking <= 0 then
				if ActiveConnection then
					ActiveConnection:Disconnect()
					ActiveConnection = nil
					warn(ActiveConnection, "Noooooo it end already, Active attacks: " .. #ActiveAttacks .. ", Active CDs: " .. CountActiveCDs() .. ", Active Stored Attacks: " .. #StoreAttacks .. ", Active Store Loop DMG Modules: " .. #StoreLoopDMGAttacks .. ", Active NPC Tracking: " .. #StoreNPCTracking)
					if #ActiveAttacks > 0 or CountActiveCDs() > 0 or #StoreAttacks > 0 or #StoreLoopDMGAttacks > 0 or #StoreNPCTracking > 0 then
						warn("There still remaining left")
						CharStuffs:CheckConnection()
					end
					return
				end
			end
			
			for PlrChar, TableValues in pairs(ActiveCDS) do
				if not PlrChar or not PlrChar.Parent then
					if ActiveCDS[PlrChar] then
						ActiveCDS[PlrChar] = nil
					end
					continue
				end
				
				for TheInstance, ValueStuff in pairs(TableValues) do
					if not PlrChar or not PlrChar.Parent then
						if ActiveCDS[PlrChar] then
							ActiveCDS[PlrChar] = nil
						end
						continue
					end
					
					if not TheInstance or not TheInstance.Parent then continue end
					if ValueStuff[4] and ValueStuff[4] == true then continue end
					if os.clock() - ValueStuff[3] > ValueStuff[2] then
						if TheInstance then
							if TheInstance:IsA("Tool") and TheInstance:GetAttribute("OGName") then
								TheInstance.Name = TheInstance:GetAttribute("OGName")
								TheInstance.Enabled = true
							elseif TheInstance:IsA("TextButton") and TheInstance:GetAttribute("OGText") then
								TheInstance.Text = TheInstance:GetAttribute("OGText")
								if TheInstance:GetAttribute("OnCD") then
									TheInstance:SetAttribute("OnCD", nil)
								end
							end
						end
						
						if PlrChar and ActiveCDS[PlrChar][TheInstance] then
							ActiveCDS[PlrChar][TheInstance] = nil
						elseif not PlrChar or not PlrChar.Parent then
							if ActiveCDS[PlrChar] then
								ActiveCDS[PlrChar] = nil
							end
						end
						continue
					end
					
					if TheInstance and TheInstance:IsA("Tool") then
						TheInstance.Name = math.round((ValueStuff[2] - (os.clock() - ValueStuff[3])) * 10) / 10
					elseif TheInstance and TheInstance:IsA("TextButton") then
						TheInstance.Text = math.round((ValueStuff[2] - (os.clock() - ValueStuff[3])) * 10) / 10
					end
				end
			end
			
			for k, v in pairs(ActiveAttacks) do
				if not v[1] or not v[1].Parent or not v[2] or not v[3] or not v[4] or not v[4].Parent or not v[5] or not v[5].Parent then 
				--	warn(k, v[1], v[1].Parent, v[2], v[3], v[4], v[4].Parent, v[5], v[5].Parent, v, " Nil values ", "-- Line 137") 
					if v[1] then
						v[1]:Destroy()
					end
					if v[5] then
						v[5]:Destroy()
					end
					table.remove(ActiveAttacks, k) 
					continue 
				end
				
				local AttackParams = AttackParamsModule:ReturnTheParams()
				local DMG, DB = v[2]["DMG"] or 0 , v[2]["Debounce"] or 0.1
				
				local GetTheHitbox 
				if v[2]["HitboxType"] and v[2]["HitboxType"] == "Box" then
					local CFrameOffsets, TheSizeMultiplier, TheSizeIncrease = v[2]["CFrameOffsets"] or CFrame.new(0, 0, 0) , v[2]["SizeMultiplier"] or 1 , v[2]["SizeIncrease"] or Vector3.zero
					GetTheHitbox = workspace:GetPartBoundsInBox(v[5].CFrame * CFrameOffsets, (v[5].Size * TheSizeMultiplier) + TheSizeIncrease, AttackParams)
				elseif v[2]["HitboxType"] and v[2]["HitboxType"] == "Radius" then
					local PosOffsets, TheSizeMultiplier, TheSizeIncrease = v[2]["PositionOffsets"] or Vector3.zero , v[2]["SizeMultiplier"] or 1 , v[2]["SizeIncrease"] or 0
					GetTheHitbox = workspace:GetPartBoundsInRadius(v[5].Position + PosOffsets, ((v[5].Size.X * TheSizeMultiplier) + TheSizeIncrease) / 2, AttackParams)
				end
				
				if v[1] and v[1]:GetAttribute("ExtraDMG") then
					DMG += v[1]:GetAttribute("ExtraDMG")
				end
				
				if not GetTheHitbox then warn("No Hitbox. Line 164") continue end
				for __, h in pairs(GetTheHitbox) do
					if not h or not h.Parent then continue end
					if v["PausedAttack"] then continue end
					if not h.Parent:FindFirstChildOfClass("Humanoid") or h.Parent:FindFirstChildOfClass("Humanoid").Health <= 0 then continue end
					if not h.Parent:FindFirstChild("HumanoidRootPart") or not h.Parent:FindFirstChild("Torso") then continue end
					if table.find(v[3], h.Parent) then continue end
					if not v[4] or not v[4].Parent then continue end
					
					table.insert(v[3], h.Parent)
					if DB then
						task.delay(DB, function()
							if not h or not h.Parent or not table.find(v[3], h.Parent) then return end
							table.remove(v[3], table.find(v[3], h.Parent))
						end)
					end
					
					local TheChar:Model = h.Parent
					local TheHumRoot:Part = TheChar:FindFirstChild("HumanoidRootPart")
					local TheTorso:Part = TheChar:FindFirstChild("Torso")
					local TheHumanoid:Humanoid = TheChar:FindFirstChildOfClass("Humanoid")
					
					if v["PausedAttack"] then continue end
					local TakeDMG = GeneralModule:TakeDamage(nil, v[4], TheChar, {DMG})
					if TakeDMG and tonumber(TakeDMG) then
						if v[2]["CustomEffect"] and typeof(v[2]["CustomEffect"]) == "function" then
							v[2]["CustomEffect"](TheChar)
						end
					end
				end
				
				if v[1]:FindFirstChild("CustomFunction") then
					require(v[1]:FindFirstChild("CustomFunction")):Function(t)
				end
			end
			
			for k, v in pairs(StoreAttacks) do
				if not v["ThePlayer"] or not v["ThePlayer"].Parent or not v["TheAttack"] or not v["TheAttack"].Parent then
					if v["TheAttack"] then
						v["TheAttack"]:Destroy()
					end
					table.remove(StoreAttacks, k) 
					continue 
				end
			--	print(v["DestroyIfCharNil"], v["ThePlayerCharacter"], v["ThePlayerCharacter"].Parent)
				if v["DestroyIfCharNil"] and (not v["ThePlayerCharacter"] or not v["ThePlayerCharacter"].Parent) then
					if v["TheAttack"] then
						v["TheAttack"]:Destroy()
					end
					table.remove(StoreAttacks, k)
					continue
				end
				if v["DestroyIfCharNil2"] and v["ThePlayer"] and v["ThePlayer"].Parent and v["TheTool"] then
					if not CharStuffs:CheckConditions(v["ThePlayer"], v["TheTool"]) then
						if v["TheAttack"] then
							v["TheAttack"]:Destroy()
						end
						table.remove(StoreAttacks, k) 
						continue
					end
				end
			end
			
			for k, v in pairs(StoreLoopDMGAttacks) do
				if not v[1] or not v[1].Parent or not v[2] or not v[2].Parent or not v[3] or not v[3].Parent then
					--warn(v[1], v[1].Parent, v[2], v[2].Parent, v[3], v[3].Parent, " Nil values idk, Line 228")
					if v[2] then
						v[2]:Destroy()
					end
					table.remove(StoreLoopDMGAttacks, k)
					continue
				end
				
				require(v[3]):DamageThem(t)
			end
			
			for k, v in pairs(StoreNPCTracking) do
				if not v[1] or not v[1].Parent or 
					not v[1]:FindFirstChild("HumanoidRootPart") or not v[1]:FindFirstChild("HumanoidRootPart").Parent or
					not v[1]:FindFirstChild("Torso") or not v[1]:FindFirstChild("Torso").Parent or
					not v[1]:FindFirstChildOfClass("Humanoid") or not v[1]:FindFirstChildOfClass("Humanoid").Parent or
					v[1]:FindFirstChildOfClass("Humanoid").Health <= 0 or 
					v[1]:FindFirstChildOfClass("Humanoid"):GetState() == Enum.HumanoidStateType.Dead then
					
					table.remove(StoreNPCTracking, k)
					continue
				end
				
				if v[1]:GetAttribute("PauseTracking") then continue end
				TrackingTime(v[1])
			end
			
			-- print(ActiveConnection, t .. ", end run of module loop, Active attacks: " .. #ActiveAttacks .. ", Active CDs: " .. CountActiveCDs() .. ", Active Stored Attacks: " .. #StoreAttacks .. ", Active Store Loop DMG Modules: " .. #StoreLoopDMGAttacks .. ", Active NPC Tracking: " .. #StoreNPCTracking)
		end)
	end
end

Any suggestion is appreciated!

More error handling in your heartbeat to pinpoint the actual error:

updated function on your heart beat

function CharStuffs:CheckConnection()
	if ActiveConnection then 
		warn(ActiveConnection, "there already connection, Active attacks: " .. #ActiveAttacks .. ", Active CDs: " .. CountActiveCDs() .. ", Active Stored Attacks: " .. #StoreAttacks .. ", Active Store Loop DMG Modules: " .. #StoreLoopDMGAttacks .. ", Active NPC Tracking: " .. #StoreNPCTracking) 
		return
	end
	
	local function handleError(err)
		warn("Error in Heartbeat loop: ", err)
	end
	
	if not ActiveConnection then
		ActiveConnection = RS.Heartbeat:Connect(function(t)
			local success, err = pcall(function()
				-- Your existing code here
				
				-- Example of additional logging
				print("Heartbeat running, Active attacks: " .. #ActiveAttacks .. ", Active CDs: " .. CountActiveCDs() .. ", Active Stored Attacks: " .. #StoreAttacks .. ", Active Store Loop DMG Modules: " .. #StoreLoopDMGAttacks .. ", Active NPC Tracking: " .. #StoreNPCTracking)
			end)
			
			if not success then
				handleError(err)
			end
		end)
	end
end

Okay thanks, ill try this and report again the status if i encounter one in game

Sadly it still broke and no warn error output
You can see its stacking and the Heartbeat running loop stopped sending output