Failed to establish connection with the Relay server.

I was troubleshooting this all day long with no hope. I’m trying to join a lobby using a relay to establish a connection between two instances of my game on two different PCs but the client instance just times out trying to reach the host with no hope and it gives those errors on the host instance after 3 seconds:

1. Failed to establish connection with the Relay server.
0x00007ff73ad0eaba (Unity) DefaultBurstRuntimeLogCallback
2. Transport failure! Relay allocation needs to be recreated, and NetworkManager restarted. Use NetworkManager.OnTransportFailure to be notified of such events programmatically.
3. [Netcode] Host is shutting down due to network transport failure of UnityTransport!

NOTE: My Internet connection is more than excellent on the two devices and I have set up the lobby and relay services correctly on the Unity website. And I’m new to the game-making world.

Here is what I have tried but it gives the error:
```csharp
**using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using Unity.Networking.Transport.Relay;
using Unity.Services.Authentication;
using Unity.Services.Core;
using Unity.Services.Lobbies;
using Unity.Services.Lobbies.Models;
using Unity.Services.Relay;
using Unity.Services.Relay.Models;
using UnityEngine;
using UnityEngine.SceneManagement;

public class KitchenGameLobby : MonoBehaviour {

private const string KEY_RELAY_JOIN_CODE = "RelayJoinCode";


public static KitchenGameLobby Instance { get; private set; }


public event EventHandler OnCreateLobbyStarted;
public event EventHandler OnCreateLobbyFailed;
public event EventHandler OnJoinStarted;
public event EventHandler OnQuickJoinFailed;
public event EventHandler OnJoinFailed;
public event EventHandler<OnLobbyListChangedEventArgs> OnLobbyListChanged;
public class OnLobbyListChangedEventArgs : EventArgs {
    public List<Lobby> lobbyList;
}



private Lobby joinedLobby;
private float heartbeatTimer;
private float listLobbiesTimer;


private void Awake() {
    Instance = this;

    DontDestroyOnLoad(gameObject);

    InitializeUnityAuthentication();
}

private async void InitializeUnityAuthentication() {
    if (UnityServices.State != ServicesInitializationState.Initialized) {
        InitializationOptions initializationOptions = new InitializationOptions();
        //initializationOptions.SetProfile(UnityEngine.Random.Range(0, 10000).ToString());

        await UnityServices.InitializeAsync(initializationOptions);

        await AuthenticationService.Instance.SignInAnonymouslyAsync();
    }
}

private void Update() {
    HandleHeartbeat();
    HandlePeriodicListLobbies();
}

private void HandlePeriodicListLobbies() {
    if (joinedLobby == null &&
        UnityServices.State == ServicesInitializationState.Initialized &&
        AuthenticationService.Instance.IsSignedIn &&
        SceneManager.GetActiveScene().name == Loader.Scene.LobbyScene.ToString()) {

        listLobbiesTimer -= Time.deltaTime;
        if (listLobbiesTimer <= 0f) {
            float listLobbiesTimerMax = 3f;
            listLobbiesTimer = listLobbiesTimerMax;
            ListLobbies();
        }
    }
}


private void HandleHeartbeat() {
    if (IsLobbyHost()) {
        heartbeatTimer -= Time.deltaTime;
        if (heartbeatTimer <= 0f) {
            float heartbeatTimerMax = 15f;
            heartbeatTimer = heartbeatTimerMax;

            LobbyService.Instance.SendHeartbeatPingAsync(joinedLobby.Id);
        }
    }
}

private bool IsLobbyHost() {
    return joinedLobby != null && joinedLobby.HostId == AuthenticationService.Instance.PlayerId;
}

private async void ListLobbies() {
    try {
        QueryLobbiesOptions queryLobbiesOptions = new QueryLobbiesOptions {
            Filters = new List<QueryFilter> {
              new QueryFilter(QueryFilter.FieldOptions.AvailableSlots, "0", QueryFilter.OpOptions.GT)
         }
        };
        QueryResponse queryResponse = await LobbyService.Instance.QueryLobbiesAsync(queryLobbiesOptions);

        OnLobbyListChanged?.Invoke(this, new OnLobbyListChangedEventArgs {
            lobbyList = queryResponse.Results
        });
    } catch (LobbyServiceException e) {
        Debug.Log(e);
    }
}


private async Task<Allocation> AllocateRelay() {
    try {
        Allocation allocation = await RelayService.Instance.CreateAllocationAsync(KitchenGameMultiplayer.MAX_PLAYER_AMOUNT - 1);

        return allocation;
    } catch (RelayServiceException e) {
        Debug.Log(e);

        return default;
    }
}

private async Task<string> GetRelayJoinCode(Allocation allocation) {
    try {
        string relayJoinCode = await RelayService.Instance.GetJoinCodeAsync(allocation.AllocationId);

        return relayJoinCode;
    } catch (RelayServiceException e) {
        Debug.Log(e);
        return default;
    }
}

private async Task<JoinAllocation> JoinRelay(string joinCode) {
    try {
        JoinAllocation joinAllocation = await RelayService.Instance.JoinAllocationAsync(joinCode);
        return joinAllocation;
    } catch (RelayServiceException e) {
        Debug.Log(e);
        return default;
    }
}


public async void CreateLobby(string lobbyName, bool isPrivate) {
    OnCreateLobbyStarted?.Invoke(this, EventArgs.Empty);
    try {
        joinedLobby = await LobbyService.Instance.CreateLobbyAsync(lobbyName, KitchenGameMultiplayer.MAX_PLAYER_AMOUNT, new CreateLobbyOptions {
            IsPrivate = isPrivate,
        });

        Allocation allocation = await AllocateRelay();

        string relayJoinCode = await GetRelayJoinCode(allocation);

        await LobbyService.Instance.UpdateLobbyAsync(joinedLobby.Id, new UpdateLobbyOptions {
            Data = new Dictionary<string, DataObject> {
                 { KEY_RELAY_JOIN_CODE , new DataObject(DataObject.VisibilityOptions.Member, relayJoinCode) }
             }
        });

        NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(new RelayServerData(allocation, "dtls"));
      
      

        KitchenGameMultiplayer.Instance.StartHost();
        Loader.LoadNetwork(Loader.Scene.CharacterSelectScene);
    } catch (LobbyServiceException e) {
        Debug.Log(e);
        OnCreateLobbyFailed?.Invoke(this, EventArgs.Empty);
    }
}

public async void QuickJoin() {
    OnJoinStarted?.Invoke(this, EventArgs.Empty);
    try {
        joinedLobby = await LobbyService.Instance.QuickJoinLobbyAsync();

        string relayJoinCode = joinedLobby.Data[KEY_RELAY_JOIN_CODE].Value;

        JoinAllocation joinAllocation = await JoinRelay(relayJoinCode);

        NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(new RelayServerData(joinAllocation, "dtls"));

        KitchenGameMultiplayer.Instance.StartClient();
    } catch (LobbyServiceException e) {
        Debug.Log(e);
        OnQuickJoinFailed?.Invoke(this, EventArgs.Empty);
    }
}

public async void JoinWithId(string lobbyId) {
    OnJoinStarted?.Invoke(this, EventArgs.Empty);
    try {
        joinedLobby = await LobbyService.Instance.JoinLobbyByIdAsync(lobbyId);

        string relayJoinCode = joinedLobby.Data[KEY_RELAY_JOIN_CODE].Value;

        JoinAllocation joinAllocation = await JoinRelay(relayJoinCode);

        NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(new RelayServerData(joinAllocation, "dtls"));

        KitchenGameMultiplayer.Instance.StartClient();
    } catch (LobbyServiceException e) {
        Debug.Log(e);
        OnJoinFailed?.Invoke(this, EventArgs.Empty);
    }
}

public async void JoinWithCode(string lobbyCode) {
    OnJoinStarted?.Invoke(this, EventArgs.Empty);
    try {
        joinedLobby = await LobbyService.Instance.JoinLobbyByCodeAsync(lobbyCode);

        string relayJoinCode = joinedLobby.Data[KEY_RELAY_JOIN_CODE].Value;

        JoinAllocation joinAllocation = await JoinRelay(relayJoinCode);

        NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(new RelayServerData(joinAllocation, "dtls"));

        KitchenGameMultiplayer.Instance.StartClient();
    } catch (LobbyServiceException e) {
        Debug.Log(e);
        OnJoinFailed?.Invoke(this, EventArgs.Empty);
    }
}

public async void DeleteLobby() {
    if (joinedLobby != null) {
        try {
            await LobbyService.Instance.DeleteLobbyAsync(joinedLobby.Id);

            joinedLobby = null;
        } catch (LobbyServiceException e) {
            Debug.Log(e);
        }
    }
}

public async void LeaveLobby() {
    if (joinedLobby != null) {
        try {
            await LobbyService.Instance.RemovePlayerAsync(joinedLobby.Id, AuthenticationService.Instance.PlayerId);

            joinedLobby = null;
        } catch (LobbyServiceException e) {
            Debug.Log(e);
        }
    }
}

public async void KickPlayer(string playerId) {
    if (IsLobbyHost()) {
        try {
            await LobbyService.Instance.RemovePlayerAsync(joinedLobby.Id, playerId);
        } catch (LobbyServiceException e) {
            Debug.Log(e);
        }
    }
}


public Lobby GetLobby() {
    return joinedLobby;
}

}**
```

I followed @CodeMonkeyYT Course on YouTube and my code is identical to his I even tried his code, but it gives the same error.

did you setup UGS in the UGS dashboard?

Whats is UGS?

Unity Game Services

If you mean the the organization and the project and linking them with adding the relay and the lobby then yes.

have you tried udp? rather than dtls? dunno if that would help

I tried yes but with no help

Is the client using the relay code that the host created?

The code changes every time the host starts a game with relay enabled, and the client will need to manually enter this code every time before joining.

What is relay code? You mean lobby code? The only info i can say here is that it was working fine before i added the relay package and wrote the relay code but was running locally of course.

I’m starting to feeling that i will not make any more games because i worked so hard on this and don’t know why it doesn’t work properly…

Suspected issues:

  1. Some updates to the lobby/relay/netcode/unity transport components has altered the way they work with this code. So in other words this code is outdated with the latest updates.

  2. Unity Version.

its easy to feel dejected when it doesnt work - but ahving recently learnt the netgame objects stuff, i got there, and am happy i understand why my stuff works.

If you think its your versions, list your unity version and all the versions of the ugs portions you are using.

My main thought is you’re possibly using relay and lobby round the wrong way.

You havent actually said whether its host or client that fails, but…

looking at

           joinedLobby = await LobbyService.Instance.CreateLobbyAsync(lobbyName, KitchenGameMultiplayer.MAX_PLAYER_AMOUNT, [URL='http://www.google.com/search?q=new+msdn.microsoft.com']new[/URL] CreateLobbyOptions {
                IsPrivate = isPrivate,
          });

           Allocation allocation = await AllocateRelay();

            string relayJoinCode = await GetRelayJoinCode(allocation);


            await LobbyService.Instance.UpdateLobbyAsync(joinedLobby.Id, [URL='http://www.google.com/search?q=new+msdn.microsoft.com']new[/URL] UpdateLobbyOptions {
                Data = [URL='http://www.google.com/search?q=new+msdn.microsoft.com']new[/URL] Dictionary<string, DataObject> {
                     { KEY_RELAY_JOIN_CODE , [URL='http://www.google.com/search?q=new+msdn.microsoft.com']new[/URL] DataObject(DataObject.VisibilityOptions.Member, relayJoinCode) }
                 }
            });


            NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData([URL='http://www.google.com/search?q=new+msdn.microsoft.com']new[/URL] RelayServerData(allocation, "dtls"));
        
        

            KitchenGameMultiplayer.Instance.StartHost();
            Loader.LoadNetwork(Loader.Scene.CharacterSelectScene);
        } catch (LobbyServiceException e) {
            Debug.Log(e);
            OnCreateLobbyFailed?.Invoke(this, EventArgs.Empty);

Now, I run a server and a client not a host and a client… but

I use server side

                Allocation allocation = await RelayService.Instance.CreateAllocationAsync(10);
                NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(new RelayServerData(allocation, "dtls"));
                var joinCode = await RelayService.Instance.GetJoinCodeAsync(allocation.AllocationId);
                Status.Message("Join code: "+joinCode);
                currentLobby.Data["relay"] = new DataObject(DataObject.VisibilityOptions.Member,joinCode,0);
                await LobbyService.Instance.UpdateLobbyAsync(currentLobby.Id, new UpdateLobbyOptions()
                {
                    Data = currentLobby.Data
                });

and client

List<QueryFilter> queryFilters = new List<QueryFilter>
{
};

// Query results can also be ordered
// The query API supports multiple "order by x, then y, then..." options
// Order results by available player slots (least first), then by lobby age, then by lobby name
List<QueryOrder> queryOrdering = new List<QueryOrder>
{
    new QueryOrder(true, QueryOrder.FieldOptions.AvailableSlots),
    new QueryOrder(false, QueryOrder.FieldOptions.Created),
    new QueryOrder(false, QueryOrder.FieldOptions.Name),
};

// Call the Query API
QueryResponse response = await LobbyService.Instance.QueryLobbiesAsync(new QueryLobbiesOptions()
{
    Count =1, // Override default number of results to return
    Filters = queryFilters,
    Order = queryOrdering,
});

List<Lobby> foundLobbies = response.Results;

if (foundLobbies.Any()) // Try to join a random lobby if one exists
{
    // Let's print info about the lobbies we found
    Status.Message("Found lobbies:\n" + JsonConvert.SerializeObject(foundLobbies));

    // Let's pick a random lobby to join
    var randomLobby = foundLobbies[0];

    // Try to join the lobby
    // Player is optional because the service can pull the player data from the auth token
    // However, if your player has custom data, you will want to pass the Player object into this call
    // This will save you having to do a Join call followed by an UpdatePlayer call
    currentLobby = await LobbyService.Instance.JoinLobbyByIdAsync(
    lobbyId: randomLobby.Id,
                options: new JoinLobbyByIdOptions()
                {
                    Player = loggedInPlayer
                });

            Status.Message($"Joined lobby {currentLobby.Name} ({currentLobby.Id})");
            Status.Message("Waiting on join code");
            while (true)
            {
                await Awaitable.WaitForSecondsAsync(5);
                if (!string.IsNullOrEmpty(currentLobby.Data["relay"].Value))
                {
                    Status.Message($"Starting game");
                    var joinAllocation = await RelayService.Instance.JoinAllocationAsync(joinCode: currentLobby.Data["relay"].Value);
                    NetworkManager.Singleton.RunInBackground = true;
                    Status.Message("Joining server");
                    NetworkManager.Singleton.StartClient();

Mine works just fine, even from a docker container :stuck_out_tongue:

SOLVED!

I don’t know what fixed the issue exactly but apparently, reinstalling Unity Transport fixed the issue!

when I just changed dtls to udp it didn’t make any difference and as I suspected the error was caused by its installation and version so I removed it from the package manager and installed UnityTransport 2.0.0-pre.3 AND IT WORKED but when I revert to dtls it does not work and gives the same error so I guess using udp along with reinstalling/downgrading Unity Transport helped fix the issue. ALSO updated to version unity 2022.3.20f1

Thanks so much to you all and yes @bugfinders it is sad sometimes when I’m excited about something and it fails me but that is the nature of coding you have to write, test, fix, and repeat. I think that is how you got there.

Related thread: UnityTransport SetRelayServerData and RelayServerData not working?

oh dont get me wrong, it is especially hard when you’re new at something and it spits in your face, it might as well often say “error there was an error” … for all the help its message means, and more over, it isnt always something you wrote, but maybe you offended it by selecting something… earlier today i was playing with the new ui toolkit stuff, as frankly hadnt done enough and i clicked and unity poof’d didnt even do the “i crashed log a bug” thing… gone… flat gone… all changes i hadnt saved… gone… you just dont think clicking on a UI thing would achieve that.

Sometimes it is because we are new and we grasp at a few straws, we find bugs others dont because they know what they are doing and so just never go there…

I don’t know what to say other than you are 100% right honestly I can’t thank you enough for these words they are a motivator for me and indeed new things come with completely new issues but great thing Unity has this forum with beautiful people like you who care to help. Oh, and the changes you haven’t saved that are gone after you clicked on something THAT happened to me a lot especially when I faced power outages so it’s so annoying to rebuild it again.

1 Like