Error after leaving and joining for a few times. - An item with the same key has already been added

Hello, we’ve recently decided to setup Lobby service. Everything works fine and here’s the join code we are currently using;

        public static async UniTaskVoid JoinLobby(Lobby lobby)
        {
            try
            {
                SetActiveLobby(await LobbyService.Instance.JoinLobbyByIdAsync(lobby.Id, new JoinLobbyByIdOptions { Player = GetPlayer() }));
                OnJoinedLobby?.Invoke(lobby);
            }
            catch (LobbyServiceException e)
            {
                CaughtError(e);
            }
        }

SetActivePlayer just casts the lobby to a static field called currentLobby, and then we trigger an event to update the UI etc. If anything fails there’s also a try catch block to help us.

Now the problem is when a client decides to leave and rejoin the lobby a few times (at least 2 times) we get the following error thrown. I couldn’t come up with anything and thought It was maybe about LobbyPatcher.cs?

The user leaves with this method as documented.


        public static async UniTaskVoid LeaveLobby()
        {
            try
            {
                await LobbyService.Instance.RemovePlayerAsync(GetActiveLobby().Id, UnityServiceAuthenticator.GetPlayerProfile().PlayerId);
                SetActiveLobby(null);
                OnLeftLobby?.Invoke();
            }
            catch (LobbyServiceException e)
            {
                Debug.LogException(e);
            }
        }

Any help would be greatly appreciated.

ArgumentException: An item with the same key has already been added. Key: hNhnfCudz24uXpxl7GB4mEQU5TVk
System.Collections.Generic.Dictionary`2[TKey,TValue].TryInsert (TKey key, TValue value, System.Collections.Generic.InsertionBehavior behavior) (at <321eb2db7c6d43ea8fc39b54eaca3452>:0)
System.Collections.Generic.Dictionary`2[TKey,TValue].Add (TKey key, TValue value) (at <321eb2db7c6d43ea8fc39b54eaca3452>:0)
LobbyPatcher.GetLobbyDiff (Unity.Services.Lobbies.Models.Lobby lobby1, Unity.Services.Lobbies.Models.Lobby lobby2) (at ./Library/PackageCache/com.unity.services.multiplayer/Runtime/Lobbies/SDK/LobbyUpdates/Internal/LobbyPatcher.cs:308)
Lobbies.SDK.LobbyCacher.LobbyCacher.UpdateLobbyCache (System.String lobbyId, Unity.Services.Lobbies.Models.Lobby newLobby) (at ./Library/PackageCache/com.unity.services.multiplayer/Runtime/Lobbies/SDK/LobbyCacher/LobbyCacher.cs:63)
Unity.Services.Lobbies.Internal.WrappedLobbyService.AddOrUpdateLobbyCache (Unity.Services.Lobbies.Models.Lobby newLobby) (at ./Library/PackageCache/com.unity.services.multiplayer/Runtime/Lobbies/SDK/WrappedLobbyService.cs:617)
Unity.Services.Lobbies.Internal.WrappedLobbyService.JoinLobbyByIdAsync (System.String lobbyId, Unity.Services.Lobbies.JoinLobbyByIdOptions options) (at ./Library/PackageCache/com.unity.services.multiplayer/Runtime/Lobbies/SDK/WrappedLobbyService.cs:218)
_Project.Modules.NetworkModule.Core.Lobbies.Scripts.LobbyManager.JoinLobby (Unity.Services.Lobbies.Models.Lobby lobby) (at F:/Unity Projects/Project Gang/Assets/_Project/Modules/NetworkModule/Core/Lobbies/Scripts/LobbyManager.cs:137)
UnityEngine.DebugLogHandler:LogException(Exception, Object)
_Project.Modules.LogHandlerModule.Scripts.CustomLogHandler:LogException(Exception, Object) (at F:/Unity Projects/Project Gang/Assets/_Project/Modules/LogHandlerModule/Scripts/CustomLogHandler.cs:61)
UnityEngine.Debug:LogException(Exception)
Cysharp.Threading.Tasks.UniTaskScheduler:PublishUnobservedTaskException(Exception) (at ./Library/PackageCache/com.cysharp.unitask/Runtime/UniTaskScheduler.cs:90)
_Project.Modules.NetworkModule.Core.Lobbies.Scripts.<JoinLobby>d__18:MoveNext() (at F:/Unity Projects/Project Gang/Assets/_Project/Modules/NetworkModule/Core/Lobbies/Scripts/LobbyManager.cs:143)
Cysharp.Threading.Tasks.CompilerServices.AsyncUniTaskVoid`1:Run() (at ./Library/PackageCache/com.cysharp.unitask/Runtime/CompilerServices/StateMachineRunner.cs:104)
System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1:SetException(Exception)
Unity.Services.Lobbies.Internal.<JoinLobbyByIdAsync>d__18:MoveNext() (at ./Library/PackageCache/com.unity.services.multiplayer/Runtime/Lobbies/SDK/WrappedLobbyService.cs:233)
System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1:SetResult(Response`1)
Unity.Services.Lobbies.Internal.<TryCatchRequest>d__28`2:MoveNext() (at ./Library/PackageCache/com.unity.services.multiplayer/Runtime/Lobbies/SDK/WrappedLobbyService.cs:458)
System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1:SetResult(Response`1)
Unity.Services.Lobbies.Apis.Lobby.<JoinLobbyByIdAsync>d__16:MoveNext() (at ./Library/PackageCache/com.unity.services.multiplayer/Runtime/Lobbies/Apis/LobbyApi.cs:506)
System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1:SetResult(HttpClientResponse)
Unity.Services.Lobbies.Http.<MakeRequestAsync>d__1:MoveNext() (at ./Library/PackageCache/com.unity.services.multiplayer/Runtime/Lobbies/Http/HttpClient.cs:41)
System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1:SetResult(HttpClientResponse)
Unity.Services.Lobbies.Http.<CreateWebRequestAsync>d__3:MoveNext() (at ./Library/PackageCache/com.unity.services.multiplayer/Runtime/Lobbies/Http/HttpClient.cs:56)
System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1:SetResult(HttpClientResponse)
Unity.Services.Lobbies.Http.<CreateHttpClientResponse>d__4:MoveNext() (at ./Library/PackageCache/com.unity.services.multiplayer/Runtime/Lobbies/Http/HttpClient.cs:84)
System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1:SetResult(HttpClientResponse)
Unity.Services.Lobbies.Http.<<CreateHttpClientResponse>b__0>d:MoveNext() (at ./Library/PackageCache/com.unity.services.multiplayer/Runtime/Lobbies/Http/HttpClient.cs:81)
System.Threading.Tasks.TaskCompletionSource`1:SetResult(HttpClientResponse)
Unity.Services.Lobbies.Http.<>c__DisplayClass0_0:<GetAwaiter>b__0(AsyncOperation) (at ./Library/PackageCache/com.unity.services.multiplayer/Runtime/Lobbies/Http/UnityWebRequestHelpers.cs:34)
UnityEngine.AsyncOperation:InvokeCompletionEvent()
1 Like

Are all the calls properly awaited?

I have a hunch that the player may be able to join again before LeaveLobby has completed.
Or the Lobby host needs to perform some cleanup after players leave such as removing their Lobby state.

Hi @eferun ,
Thank you for your report (especially for the call stack, it helps us a lot). We received multiple reports of this issue and we are actively investigating it !

Hello, @ArthurAtUnity.

Great to hear you’re actively investigating the issue! I’m glad the call stack was helpful, let me know if there’s anything else I can provide to assist further.

Hi @eferun ,

We successfully reproduced this bug and we believe we found both the root cause and a fix :+1:
However I can’t commit to any ETA for the release of this fix yet

1 Like

Hi, @ArthurAtUnity

That’s awesome to hear! I’ll be on the lookout for it. Thanks so much!

Any ETA at this point? Its blocking me from progressing on my game, and I’d love to see if this actually fixes it, or if I’m still in trouble ;). Thanks!

Hi @DGordon ,
We are still trying our best to release that update as soon as possible, however, we still don’t have an ETA to provide you.

I have solved this issue.
I fixed it by commenting out part of the AddOrUpdateLobbyCache method in the WrappedLobbyService class.
There are no problems so far, but is it okay to use it this way?

        internal void AddOrUpdateLobbyCache(Models.Lobby newLobby)
        {
            //var lobbyCacheExists = m_LobbyCacher.TryGetLobbyCache(newLobby.Id, out Models.Lobby _);
            //if (!lobbyCacheExists)
            //{
            //    m_LobbyCacher.AddLobbyCache(newLobby.Id, newLobby);
            //    return;
            //}

            m_LobbyCacher.UpdateLobbyCache(newLobby.Id, newLobby);
        }

Hi @heewoung ,

TLDR; it might fix this issue but might disrupt session events.

Please note I am referring to Lobby because it is still the underlying system, but in this explanation, we can almost interchange it with the sessions and sessions events.

The Lobby cache is used to diff between Lobby states and to make sure Lobby events are properly being propagated through the callbacks. The issue origin is in our handling of those Lobby state diff. When you disable the call to AddLobbyCache, the Lobby is never added to the cache, which result in diff never being created.
Please note that the Lobby events can still be forwarded by the Lobby backend server, however local checks for the order they were received in and potential missing events won’t be properly executed.

The actual fix in our logic has already been made and it will be included in the new release. We are still doing our best to release as soon as possible.

1 Like

Oh, thank you. I was wrong.
When handled in my response style, the lobby callback doesn’t work.

Thank you! I have confirmed that the update has been applied :slight_smile:

Package Manager->MultiPlay Services-> Version 1.1.1