"error in error handling" from a pcall

Hi, I’ve got a tower handler module for my tower defense game. Inside the tower handler there’s a tower.Attack() function that is responsible for, well, tower attacks. Everything inside it is wrapped in pcalls, yet there still seem to be errors.
obraz

function tower.Attack(newTower: Model, player: Player)
	pcall(function()
		local config = newTower:WaitForChild("Config")
		local data = newTower:WaitForChild("TowerData")

		local success, msg = pcall(function()
			if data:GetAttribute("CanAttack") == false then return end

			if data:GetAttribute("AttackCount") and config:GetAttribute("SpecialAttackMode") == "Separately" and data:GetAttribute("AttackCount") >= config.AttacksNeededForSpecial.Value then

				local target = targetModule.FindTarget(newTower, config.Range.Value, config.TargetMode.Value)
				if target and target.Attributes:GetAttribute("Health") > 0 then
					if newTower.Animations:FindFirstChild("SpecialAttack") then
						animateTowerEvent:FireAllClients(newTower, "SpecialAttack", target)
					end
					specialAttacks[config.SpecialName.Value](player, newTower, target)
					data:SetAttribute("AttackCount", 0)
				end

			else

				local amountOfShots = 1
				if config:FindFirstChild("Burst") then amountOfShots = config.Burst.Value end

				local target = targetModule.FindTarget(newTower, config.Range.Value, config.TargetMode.Value)
				if target and target:FindFirstChild("Attributes") then
					local attributes = target:FindFirstChild("Attributes")
					if (not attributes) or (attributes:GetAttribute("Health") <= 0) then return end
					local targetPos = attributes:GetAttribute("Position")

					pcall(function()
						if config:FindFirstChild("PrepTime") then
							if not data:GetAttribute("Prepared") then
								local targetCFrame = CFrame.lookAt(newTower.HumanoidRootPart.Position, Vector3.new(targetPos.X, newTower.HumanoidRootPart.Position.Y, targetPos.Z))
								newTower.HumanoidRootPart.BodyGyro.CFrame = targetCFrame
								animateTowerEvent:FireAllClients(newTower, "AttackPrep", target)
								task.wait(config:FindFirstChild("PrepTime").Value)
								data:SetAttribute("Prepared", true)
								if not target then
									target = targetModule.FindTarget(newTower, config.Range.Value, config.TargetMode.Value)
									if not target then return end
								end
							end
						end
						
						data:SetAttribute("Shooting", true)
		
						for i = 1, amountOfShots do
							target = targetModule.FindTarget(newTower, config.Range.Value, config.TargetMode.Value)
							if target and target:FindFirstChild("Attributes") and attributes:GetAttribute("Health") > 0 then
								if data:GetAttribute("AttackCount") and config:GetAttribute("SpecialAttackMode") == "Together" and data:GetAttribute("AttackCount") >= config.AttacksNeededForSpecial.Value then
									if newTower.Animations:FindFirstChild("SpecialAttack") then
										animateTowerEvent:FireAllClients(newTower, "SpecialAttack", target)
									end
									specialAttacks[config.SpecialName.Value](player, newTower, target)
									data:SetAttribute("AttackCount", 0)
								end
								attackFunctionsModule.Shoot(newTower, target, data, player, config, config:FindFirstChild("DistanceDamage"))
							end
							if amountOfShots > 1 then
								task.wait(0.15)
							end
						end
					end)

					if config:FindFirstChild("Cooldown") then
						task.wait(config.Cooldown.Value)
					else
						return
					end

				else
					data:SetAttribute("Shooting", false)
					if data:GetAttribute("Prepared") ~= nil then
						data:SetAttribute("Prepared", false)
					end
				end
			end
		end)

		if not success then warn(msg) end
		task.wait()
		if newTower and newTower.Parent then
			while (newTower.Parent) and (data:GetAttribute("Stunned") or not data:GetAttribute("CanAttack")) do
				task.wait()
			end
			tower.Attack(newTower, player)
		end
	end)
	if newTower.Parent then
		tower.Attack(newTower, player)
	end
end

Here’s the function. The error comes from the second pcall - I don’t know why. Could tell me why and help come up with a solution?

1 Like

There shouldn’t be a pcall inside a pcall

1 Like

Why is that?
And also, if I get rid of the first pcall that the next one is in, the error will not be handled in any way and it will just stop the function’s execution

You should really only use pcall for methods that require a web call such as DataStores and HttpService. In your case, it is excessive because with proper logics, none of those methods should ever fail.

As for your problem, what error do you get when you remove the pcalls?

Edit: It also seems there is an overflow issue with it in the first place. You are calling the same function again during your first pcall.

3 Likes
  1. Really? So if you have a function that can fail for whatever reason, like for exmaple a part that you want to do something with gets destroyed, it’s better to do a lot of if checks rather than wrap it all in a pcall that would automatically prevent any errors?

  2. I have removed all the pcalls, and well I don’t get the errors anymore, though I get occasional errors like “Range is not a valid member of Configuration “Config”” that used to just be handled by the pcalls

  3. The function is called inside itself all the time to ensure that it runs infinitely (so the tower keeps attacking and is always able to attack)

“error in error handling” comes from xpcall’s error handling function throwing an error, i’m not sure why it’s coming from a regular pcall here
looking through luau source code it seems that pcall only throws this error “on OOM with an error handler that errors” which seems to be coming from a memory issue/stack overflow? not sure, i didn’t even know pcall could return this error at all

2 Likes
  1. No.
    A. In your example, if a part gets destroyed and is still in memory, it can still be read (you just cant parent it).
    B. You want to fix, not avoid errors you can control.
    C. Errors are useful for terminating something to prevent the same error from happening again anyways.
    D. By that logic, you should be pcalling everything, which is wrong and is a lot more expensive operationally.
  2. That is because the pcall itself is stacking and never actually terminating. This is essentially the same as your code:
--!strict

local function func(): ()
	local success: boolean, response: any = pcall(function()
		print("test")
		func() -- this prevents your pcall from actually finishing
	end)
	
	print(success, response)
	-- with this piece of code, this will eventually stack overflow and just terminate itself
end

func()
  1. That is fine, just don’t do it in the pcall so it doesn’t run into the problem from point #2.

Remove your pcalls, read your errors, fix them.

2 Likes

I’ve never seen pcall throw that error either, that’s why I was so surprised
Thanks for giving me that extra bit of info though!

2 Likes

Okay, those are some valid points. I see the issue now, thanks for the help :slight_smile:

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.