New warning when calling task.wait(), not sure what to do

task.wait should not be called on a thread that is already ‘waiting’ in the task library


Just started one day, didn’t change anything ^^

It doesn’t break the code but I’m just confused on what this means, I tried putting wait() instead of task.wait() but it feels wrong.

--runs in a thread, a thread created for each unit in this game
    local animStopped = false
	local animEndConnect =  attackAnimTrack.Stopped:Connect(function()
		npcModule.disconnectCon(unit, "windEvent")
		npcModule.setUnitStat(unit, "LastAttack", tick())
		animStopped = true
	end)
	attackAnimTrack:Play()
	repeat task.wait() until animStopped

also for this wait

task.wait(uStats.Attributes["AttackCooldown"])

Thread its running in

function npcModule.unitThread(unit) -- resumed in another loop every .1 seconds 
	while unit and unit:FindFirstChild("Humanoid") do
		local uStats = npcModule.getUnitStats(unit)
		local closestEnemy, dist = npcModule.findClosestEnemy(unit, uStats.EnemyTeam:GetChildren())
		if closestEnemy then
			if dist and dist < uStats.Attributes["AttackRange"] then
				npcModule.setStatusAttacking(unit) -- where the error is happening
			elseif unit.Humanoid.MoveDirection.Magnitude == 0 then 
				npcModule.setStatusMoving(unit)
			end
		end
		coroutine.yield()
	end
end
function npcModule.setStatusAttacking(unit)
	npcModule.stopMove(unit)
	local uStats = npcModule.getUnitStats(unit)
	if tick() - uStats.LastAttack >= uStats.Attributes["AttackCooldown"] then
		local canAttack = false
		repeat
			if tick() - uStats.LastAttack >= uStats.Attributes["AttackCooldown"] then
				npcModule.Attack(unit) -- gives warning when waiting for anim to end
			end
			canAttack = false
			local closestEnemy, dist = npcModule.findClosestEnemy(unit, uStats.EnemyTeam:GetChildren())
			if closestEnemy then
				if dist and dist < uStats.Attributes["AttackRange"] then
					canAttack = true
					task.wait(uStats.Attributes["AttackCooldown"]) --the other warning
				end
			end
		until not canAttack 
	end
end
3 Likes

You can try to replace Attributes to uStats:GetAttribute("AttackCooldown")).
Try to see it works.

Btw, what is uStats?

This was added recently to clarify cases of unintentional behavior. How are you creating these threads? Are you keeping references to them elsewhere in your code?

Using that wait loop to stall until the animation ends, is also a strange practice. Why not simplify the whole thing among these lines?

attackAnimTrack:Play()
attackAnimTrack.Stopped:Wait()
npcModule.disconnectCon(unit, "windEvent")
npcModule.setUnitStat(unit, "LastAttack", tick())
1 Like

uStats is a dictionary of it’s anims, team, etc

1 Like
attackAnimTrack:Play()
attackAnimTrack.Stopped:Wait()
npcModule.disconnectCon(unit, "windEvent")
npcModule.setUnitStat(unit, "LastAttack", tick())


I have tried this before but for some odd reason it wouldn’t wait for the anim to stop ^^
but i just want to know why it keeps giving me this warning

I create these threads by
npcModule.addUnitStat(unit, “Threads”, “unitThread”, coroutine.create(npcModule.unitThread))
unit thread is the thread it’s running in

function npcModule.addUnitStat(unit, stat, name, val)
	unitStats[unit][stat][name] = val
end
function npcModule.createUnitStat(unit)
	--btw this is the uStats
	unitStats[unit] = {
		["Anims"] = {},
		["EnemyTeam"] = false,
		["Threads"] = {},
		["Con"] = {},
		["Debris"] = {},
		["Attributes"] = UnitAttributes[unit.Name],
		["Status"] = "Idle",
		["Dead"] = false,
		["LastAttack"] = 0,
		["Frozen"] = false
	}
	return unitStats[unit]
end
1 Like

What is UnitAttributes? Can you show us it please.

1 Like
local Attributes = {
	["Squire"] = {
		["Damage"] = 10,
		["AttackRange"] = 5, --5
		["AttackType"] = "Melee",
		["AttackCooldown"] = .75,
		["Cooldown"] = 3,
		["Knockbacks"] = 3,
		["DeathSoundChance"] = .5,
		["Price"] = 50,
		["Image"] = "rbxassetid://15539281911",
	},
	["Spearman"] = {
		["Damage"] = 5,
		["AttackRange"] = 7.5,
		["AttackType"] = "Melee",
		["AttackCooldown"] = .05,
		["Cooldown"] = 4,
		["Knockbacks"] = 2,
		["DeathSoundChance"] = .5,
		["Price"] = 75,
		["Image"] = "rbxassetid://15539285114",
	},
	["Archer"] = {
		["Damage"] = 10,
		["AttackRange"] = 15,
		["AttackType"] = "Projectile_Attack",
			["RangeProjectile"] = "Arrow",
			["RangeRadius"] = 5,
			["RangeHeightMult"] = .5,
			["RangeLength"] = .5,
		["AttackCooldown"] = 2,
		["Cooldown"] = 5,
		["Knockbacks"] = 3,
		["DeathSoundChance"] = 1,
		["Price"] = 100,
		["Image"] = "rbxassetid://15539287288",
	},
	
	----------------------ENEMIES -----------------------------------------
	
	["Farmer"] = {
		["Damage"] = 5,
		["AttackRange"] = 6,
		["AttackType"] = "Melee",
		["AttackCooldown"] = .5,
		["Knockbacks"] = 2,
		["DeathSoundChance"] = .5,
	},
	["Harvester"] = {
		["Damage"] = 5,
		["AttackRange"] = 3,
		["AttackType"] = "Melee",
		["AttackCooldown"] = .75,
		["Knockbacks"] = 3,
		["DeathSoundChance"] = .5,
	},
	["Rancher"] = {
		["Damage"] = 20,
		["AttackRange"] = 5,
		["AttackType"] = "Melee",
		["AttackCooldown"] = 2,
		["Knockbacks"] = 1,
		["AttackAOE"] = {
			["Radius"] = 4,
			["Offset"] = 3,
			["Pos"] = "Self",
			["RepeatSound"] = true
		},
		["DeathSoundChance"] = 1,
	},
	["Forester"] = {
		["Damage"] = 50,
		["AttackRange"] = 5,
		["AttackType"] = "Melee",
		["AttackCooldown"] = 1,
		["Knockbacks"] = 5,
		["DeathSoundChance"] = .75,
	},
}

also, i added unitThread(the thread it’s erroring on) in the top post

Try task.wait(2) to see if it waits 2 seconds because it might be something to do with finding the number

1 Like

Still warning me, not sure why it won’t let me record but i got a screenshot

1 Like

I meant for this: task.wait(uStats.Attributes["AttackCooldown"])

1 Like

Still gives me warnings sadly :frowning:

when i set it to wait() it doesn’t error, is wait() and task.wait() 2 different things? And would it be alright if I just set it to wait()?

1 Like

Roblox said someday wait() will become deprecated and I think task.wait is more performant. I think its because you’ve got that task.wait in that repeat wait and some reason you’re only allowed 1 wait?

EDIT: Try repeat until YOUR CODE HERE

1 Like

I don’t think these 2 are dependant of each other. I tried to comment out one of these task.wait() and the other one still warns me

Sorry I won’t answer for awhile because i need to sleep

1 Like

Hmm, alright. I’m not too sure then. Try the new Roblox assistant or chat GBT I’m not really sure.

1 Like

You mention in the update to your OP, that the unit thread is being resumed from a separate loop every tenth of second.

I figure what’s happening here, is that this external loop is prematurely resuming your task.waits, causing them to gradually stack up and produce warnings. This would also explain why you can’t simply write Stopped:Wait(); this loop is just resuming out of your other intended yields.

1 Like

The warning you’re encountering suggests an issue with calling task.wait() within a thread that is already waiting. In Lua, task.wait() (or just wait() ) is typically used to pause the execution of a coroutine until a certain condition is met. When you use task.wait() in a loop, it’s crucial to ensure that the loop condition eventually becomes false, allowing the coroutine to exit.

repeat task.wait() until animStopped

This loop is waiting until animStopped becomes true. If the animEndConnect event fires the callback (setting animStopped to true), the loop will exit. However, if there’s an issue with the event connection or the event doesn’t fire for some reason, the loop could potentially run indefinitely, causing issues.

Instead, consider using a timeout to avoid infinite loops.

local timeout = 5 -- maximum wait time in seconds
local startTime = tick()

repeat
    task.wait()
until animStopped or tick() - startTime > timeout
repeat
    task.wait(uStats.Attributes["AttackCooldown"])
until not canAttack

If canAttack is always true, or there’s some issue preventing it from becoming false, this loop could also run indefinitely. Consider adding a timeout or investigating why canAttack doesn’t become false as expected.

Here are all the scripts modified:

I put all the functions together.

    while unit and unit:FindFirstChild("Humanoid") do
        local uStats = npcModule.getUnitStats(unit)
        local closestEnemy, dist = npcModule.findClosestEnemy(unit, uStats.EnemyTeam:GetChildren())
        
        if closestEnemy then
            if dist and dist < uStats.Attributes["AttackRange"] then
                npcModule.setStatusAttacking(unit)
            elseif unit.Humanoid.MoveDirection.Magnitude == 0 then 
                npcModule.setStatusMoving(unit)
            end
        end
        
        coroutine.yield()
    end
end

function npcModule.setStatusAttacking(unit)
    npcModule.stopMove(unit)
    local uStats = npcModule.getUnitStats(unit)

    if tick() - uStats.LastAttack >= uStats.Attributes["AttackCooldown"] then
        local timeout = 5
        local startTime = tick()

        repeat
            if tick() - uStats.LastAttack >= uStats.Attributes["AttackCooldown"] then
                npcModule.Attack(unit)
            end

            local closestEnemy, dist = npcModule.findClosestEnemy(unit, uStats.EnemyTeam:GetChildren())

            if closestEnemy and dist and dist < uStats.Attributes["AttackRange"] then
                task.wait(uStats.Attributes["AttackCooldown"])
            end
        until not (tick() - startTime > timeout)
    end
end

local animStopped = false
local timeout = 5
local startTime = tick()

local animEndConnect = attackAnimTrack.Stopped:Connect(function()
    npcModule.disconnectCon(unit, "windEvent")
    npcModule.setUnitStat(unit, "LastAttack", tick())
    animStopped = true
end)

attackAnimTrack:Play()

repeat
    task.wait()
until animStopped or tick() - startTime > timeout
1 Like

Ok, so I tried the AI assistant and it suggested there should only be one line of task.wait per coroutine, or that the task.wait is being called repetitively without any other code steps.

Full reply from Roblox AI assistant

The warning message you mentioned typically occurs when you try to call task.wait() on a thread that is already waiting. This can happen if you have multiple instances of task.wait() in your code or if you have a loop that repeatedly calls task.wait() without any other code in between.

To resolve this warning, you can try the following:

  1. Check your code for any duplicate or unnecessary calls to task.wait(). Make sure you only call task.wait() when it is necessary for your logic.
  2. If you have a loop that calls task.wait() repeatedly, consider adding some other code or logic inside the loop to prevent the thread from continuously waiting. For example, you could add a condition that checks for a specific event or condition before calling task.wait() again.
  3. If you’re using task.wait() in a coroutine, make sure you’re not accidentally calling it multiple times within the same coroutine. Each coroutine should only have one instance of task.wait().

By reviewing your code and making sure you’re using task.wait() correctly, you should be able to resolve the warning about calling task.wait() on a thread that is already waiting.


By using this approach, you can ensure that task.wait() is only called when necessary and avoid any issues with calling it on a task that is already waiting.

I have also recently come across this error in my own code which I first noticed today, and I am definitely guilty of the repetitive task.wait calls… :person_shrugging:

--In a nutshell
while not condition do task.wait() end

There doesn’t seem to be any unintended behaviour from this overuse of task.wait (it still waits) so I see it more of a performance/optimisation issue at the moment rather than an error per se.
I guess switching to an event driven resumption of code would be better though by calling yield on a coroutine once, and resuming on some internal signal instead of constantly checking a condition.

So in OP’s case, using animationTrack.Ended or animationTrack.Stopped to resmue the waiting thread might work.

thank you so much, I didn’t even think of that
if anyone was wondering what i did was

while unit and unit:FindFirstChild("Humanoid") do
		npcModule.setUnitStat(unit, "NoRun", true) -- if NoRun is true then don't resume the thread
		local uStats = npcModule.getUnitStats(unit)
		local closestEnemy, dist = npcModule.findClosestEnemy(unit, uStats.EnemyTeam:GetChildren())
		if closestEnemy then
			if dist and dist < uStats.Attributes["AttackRange"] then
				npcModule.setStatusAttacking(unit)
			elseif unit.Humanoid.MoveDirection.Magnitude == 0 then 
				npcModule.setStatusMoving(unit)
			end
		end
		npcModule.setUnitStat(unit, "NoRun", false) -- allows to resume the thread
		coroutine.yield()
	end
1 Like

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