Players Leaves During GetPlayers Loop

I have code that moves players to an appropriate team and then reloads their character to move them to the spawn for that team. However, the script sometimes errors if a player leaves the game while performing theses operations.

Simplified Code:

for _,v in pairs(game.Players:GetPlayers()) do
	if v.Parent then
		v.Team = game.Teams[teamName]
		v:LoadCharacter()
	end
end

Error: “Failed to apply character appearance, player not in world.”
(Note: I’ve also had errors on the Team assignment before)

This kind of error can make sense; if the loop goes through a lot of players, it may take a while to get to the last player, and they may have left the game.

However, I read previous topics on this issue and believe my error check here should work. If the player has already left the game, v.Parent should be nil, because they are no longer in the game.

Now, I could, theoretically, just use pcall any time I want to do any interaction with player objects, but that sounds…very bad. Is there a better way to secure this loop?

if game.Players:FindFirstChild(v.Name) thne

could work here

Not really, but you can still add another sanity check.

You could add pcall() to it, pcall stops a line(s) of code when error in it occurs, so other code can run without problems. So that code would look like this :

for _,v in pairs(game.Players:GetPlayers()) do
	pcall(function()
        v.Team = game.Teams[teamName]
		v:LoadCharacter()
    end)
end

how often do you get this error?

Why not check for the character?

for _,v in pairs(game.Players:GetPlayers()) do
	if v.Character then
		v.Team = game.Teams[teamName]
		v:LoadCharacter()
	end
end
1 Like

This is also a valid solution, but is likely slower than the already existing v.Parent solution.

The inside of the check is only a couple of lines, so I don’t think this would actually fix the problem.

I was hoping to not have to do that, since it is against the standard, but I think this might be the only way to proceed.

I’d say it is significantly less than 1%, but this is part of the core game logic, so any active server will eventually run into the issue and fail once it happens a single time.

yeah so with some insane luck a person could leave the game as soon as the code go through the if and that is just inevitable so I think pcall is the only option you have

You might find coroutines useful. Since Player:LoadCharacter() yields, the players will respawn one-by-one which is why you are getting the error.
Coroutines can create a new thread for each player to respawn them all at the same time.
Read more about them here.

as Apicphis said, coroutines are probably your go-to then but I’d still recommend FindFirstChild, it works and the extra time is literally minimal

Honestly, since its a yielding function, promise is your way to go. Its a handy library which is very easy to use.

I believe u cud do smth like this

local loadCharacter = Promise.promisify(function(player)
    return player:LoadCharacter()
end)

for _, player in ipairs(Players:GetPlayers()) do
    if player then
        player.Team = game.Teams[teamName]
        characterLoad(player):catch(function(err)
            warn(err)
        end)
    end
end

As you would see, if u tried this out, it wouldn’t break the loop, as the error is caught by the function in :catch, if u also need to do something after the cahracter loads, chain an :andThen to the returning promise.

It is a grt library, and u would understand more if u check out their website and try out stuff.

1 Like

I have something like this without the warn or catch or promise, it supposed to change everyones GUI on same text and has task.wait(). If a player leaves while this scripts run, the changing of gui will realise one player is missing so it will break the whole script.

You should make a new topic instead of bumping this one, so you can mark somebody’s post as the solution if your problem was fixed.

I just want to know if their script will help even if there is a task.wait() in it but thanks for the idea