Teleporting all players in a server to the same PlaceId can teleport back to a dead server

When using TeleportService:TeleportAsync, and including all of the Players, it often causes them to teleport to a dead server, and you’ll be presented with an error such as “Roblox has shut down the server for maintenance. Please try again.” or “Client initiated disconnect”. This happens consistently in an experience with only one server and/or one player.

I believe they might be teleporting to the same server which is actively shutting down, since all of the players have been removed. This can still happen after kicking all players immediately after TeleportAsync is initiated, as it seems Roblox has already made its mind up of which server to teleport to.

This code snippet consistently reproduces this issue (as well as a place file to reproduce)

local TeleportService = game:GetService("TeleportService")
local Players = game:GetService("Players")

repeat task.wait() until Players:GetPlayers()[1] and Players:GetPlayers()[1].Character

print("Preparing to shut down")
task.wait(3)
print("Shutting down")

TeleportService:TeleportAsync(game.PlaceId, Players:GetPlayers())


System Information

CPU: Intel® Core™ i7-9700K CPU @ 3.60GHz
Memory: 16.0 GB
GPU: NVIDIA GeForce RTX 4080

Expected behavior

I expect it to realize that the current server is shutting down due to all of the players being teleported, and to always either teleport to another server, or generate a new server if one doesn’t exist. This bug makes teleporting parties of players, especially with resources like my SoftShutdown2 script which may be affected by this.

8 Likes

I’m not sure what you mean by this. There’s no other servers that are alive in this example, and the problem is that I can’t really stop Roblox from sending it back to the same server. Even if I could use a feature request for something like this, it feels unintentional that if I teleport every player in a server somewhere else, it’ll try to teleport back to the same server, when it can’t even stay alive during the transition to do so.

2 Likes

The bug report doesn’t need an output log as it’s unrelated to it - the teleport goes through just fine (also that error means if you pass something that isn’t of type TeleportOptions - TeleportOptions is a completely optional argument and isn’t needed to reproduce it).

No worries though, the report should be formatted properly.

3 Likes

I mentioned TeleportOptions just in case. I found it weird to be included in the documentation as an error and misunderstood the explanation inside of it. As long as it’s nil or a TeleportOptions object then it works (mobile web ui is trash). Sorry for the misunderstanding and my forgetful mind.

I’ve read about the error code 285 and it could be related to lag too. Could you give place URL so we can test it too? (im on phone right now my bad)

Also, just in case, have you tried to use the SafeTeleport module from Roblox? I don’t think it’s going to fix anything but just in case.

local TeleportService = game:GetService("TeleportService")

local ATTEMPT_LIMIT = 5
local RETRY_DELAY = 1
local FLOOD_DELAY = 15

local function SafeTeleport(placeId, players, options)
    local attemptIndex = 0
    local success, result -- define pcall results outside of loop so results can be reported later on

    repeat
        success, result = pcall(function()
            return TeleportService:TeleportAsync(placeId, players, options) -- teleport the user in a protected call to prevent erroring
        end)
        attemptIndex += 1
        if not success then
            task.wait(RETRY_DELAY)
        end
    until success or attemptIndex == ATTEMPT_LIMIT -- stop trying to teleport if call was successful, or if retry limit has been reached

    if not success then
        warn(result) -- print the failure reason to output
    end

    return success, result
end

local function handleFailedTeleport(player, teleportResult, errorMessage, targetPlaceId, teleportOptions)
    if teleportResult == Enum.TeleportResult.Flooded then
        task.wait(FLOOD_DELAY)
    elseif teleportResult == Enum.TeleportResult.Failure then
        task.wait(RETRY_DELAY)
    else
        -- if the teleport is invalid, report the error instead of retrying
        error(("Invalid teleport [%s]: %s"):format(teleportResult.Name, errorMessage))
    end

    SafeTeleport(targetPlaceId, {player}, teleportOptions)
end

TeleportService.TeleportInitFailed:Connect(handleFailedTeleport)

return SafeTeleport

If possible print the teleport result.

1 Like

This issue has been around for a while and it’s not straightforward to solve. The problem is that Roblox will close down a server when it’s empty and teleporting all players causes it to be momentarily empty. We have ways to track players that are in the process of connecting to a server (so that we don’t shut it down before they arrive) but in this case it doesn’t do anything since they’ve already connected.

There are ways we can solve this but it’s not simple. One way to help prioritize this would be to list out the use cases where you need to do this. The use case I know of for teleporting to the same place is to “reload” the game. Any others?

One note: this issue is not possible in SoftShutdown because the server is already marked as shutting down in BindToClose - we won’t send new players to it

5 Likes

Ah that makes sense, I incorrectly assumed that players could still join a server after BindToClose fired unless if the function ended or 30 seconds have passed. Thx for the clarification!

My use case here was that I wanted to basically ‘exclude’ the server, or mark it as not joinable in some way. I need this functionality for an admin command I wanted to add to ‘soft shutdown’ a server, which isn’t as harsh as kicking all players out of all servers for testing sessions to quickly get a new server.

Otherwise they’d have to rejoin back into the hub/start place, and then navigate to the same place they were in, and basically go through two teleports (one join, one teleport), but I’d definitely see a use case here for situations where we might want to exclude server job ids in general when teleporting, like for server hopping, or maybe the player just wants to join a different server without needing to block somebody there. Can’t really say it’s too much of a priority, just an undesirable & unexpected kink of teleporting.

Two workarounds I can think of for this is to reserve a server, or teleport them to the hub and back automatically. Considering I’d be teleporting an entire party which likely surpasses the max # of players in the Hub, and I want the server to remain a public server, I may just ditch the idea and try to deal with kicking them instead. I assume there’s no built-in method of scraping active servers for a place yet? :sweat_smile:

3 Likes

Thanks for the extra details! I’ve forwarded them to the team for discussion. A couple notes:

My use case here was that I wanted to basically ‘exclude’ the server, or mark it as not joinable in some way

If we fix this issue we would likely move in the opposite direction of what you’re trying to do here. Today, doing a matchmade join to the same Place you’re in brings you back into the same game instance. This is to support the “reload” use case I mentioned before and we would want it to work consistently. We’ve received requests to mark servers as “not joinable” before - I’ll add this to the use cases for it

I assume there’s no built-in method of scraping active servers for a place yet?

None that I know of, but I’ve seen server browsers in various games so you might be able to put something together (maybe using DataStores? You’ll have to do your own research here).

2 Likes

I am doing the exact same thing as he is. I decided to teleport users to ReservedServer, however, it still did this. Until I used TeleportService:TeleportToPrivateServer()

This is basically broken - teleporting a party from place A to place B then back to place A disconnects the party when the server hosting place A becomes empty while the party is in place B, effectively kicking everyone out of the game. I have found no way around this. Creating a private server is a hack and would disallow the party from interacting the other players unless they all left. Disappointing.

That sounds like a different issue than the one originally posted. The original issue is a problem with teleporting a player to the server they’re already in whereas you’re talking about going to a different server and back. Can you describe your issue in more detail?

Appreciate the response… it was my own bug :slight_smile: I was actually running into the exact same issue as the OP but didn’t want that behavior.

Sorry, should have come back to edit my post.

1 Like

No worries. Thanks for confirming!