{"record":{"id":"ece3e73278cc4582","repo":"ppy/osu","slug":"cannot-join-a-multiplayer-room-while-already-in-on","errorCode":null,"errorMessage":"Cannot join a multiplayer room while already in one.","messagePattern":"Cannot join a multiplayer room while already in one\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"osu.Game/Online/Multiplayer/MultiplayerClient.cs","lineNumber":261,"sourceCode":"\r\n            await joinOrLeaveTaskChain.Add(async () =>\r\n            {\r\n                await runOnUpdateThreadAsync(() => pendingRequests.Clear(), cancellationSource.Token).ConfigureAwait(false);\r\n                var multiplayerRoom = await CreateRoomInternal(new MultiplayerRoom(room)).ConfigureAwait(false);\r\n                await setupJoinedRoom(room, multiplayerRoom, cancellationSource.Token).ConfigureAwait(false);\r\n            }, cancellationSource.Token).ConfigureAwait(false);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Joins the <see cref=\"MultiplayerRoom\"/> for a given API <see cref=\"Room\"/>.\r\n        /// </summary>\r\n        /// <param name=\"room\">The API <see cref=\"Room\"/>.</param>\r\n        /// <param name=\"password\">An optional password to use for the join operation.</param>\r\n        /// <exception cref=\"InvalidOperationException\">If the current user is already in another room, or <paramref name=\"room\"/> does not represent an active room.</exception>\r\n        public async Task JoinRoom(Room room, string? password = null)\r\n        {\r\n            if (Room != null)\r\n                throw new InvalidOperationException(\"Cannot join a multiplayer room while already in one.\");\r\n\r\n            if (room.RoomID == null)\r\n                throw new InvalidOperationException(\"Cannot join an inactive room.\");\r\n\r\n            var cancellationSource = joinCancellationSource = new CancellationTokenSource();\r\n\r\n            await joinOrLeaveTaskChain.Add(async () =>\r\n            {\r\n                await runOnUpdateThreadAsync(() => pendingRequests.Clear(), cancellationSource.Token).ConfigureAwait(false);\r\n                var multiplayerRoom = await JoinRoomInternal(room.RoomID.Value, password ?? room.Password).ConfigureAwait(false);\r\n                await setupJoinedRoom(room, multiplayerRoom, cancellationSource.Token).ConfigureAwait(false);\r\n            }, cancellationSource.Token).ConfigureAwait(false);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Performs post-join setup of a <see cref=\"MultiplayerRoom\"/>.\r\n        /// </summary>\r\n        /// <param name=\"apiRoom\">The incoming API <see cref=\"Room\"/> that was requested to be joined.</param>\r","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/ppy/osu/blob/d9c73e12adff2feaae4a3e158d36fe5883faf6ca/osu.Game/Online/Multiplayer/MultiplayerClient.cs#L243-L279","documentation":"Thrown by MultiplayerClient.JoinRoom when Room is already non-null. The user may only occupy one room; a second join is treated as a programming error rather than a server request.","triggerScenarios":"Calling JoinRoom while already in a room without leaving first. Typically a UI flow bug, e.g. navigating from a room into another via a join action that did not first part the current room.","commonSituations":"Listing/lounge click that joins a new room while the previous one was not left; reconnect logic that joins again before clearing Room.","solutions":["Ensure LeaveRoom() is awaited before JoinRoom.","Gate the join control on client.Room == null.","Wrap join attempts in a helper that leaves first if needed: if (client.Room != null) await client.LeaveRoom();"],"exampleFix":"// before\nawait client.JoinRoom(room, password);\n\n// after\nif (client.Room != null)\n    await client.LeaveRoom();\nawait client.JoinRoom(room, password);","handlingStrategy":"validation","validationCode":"if (client.Room != null)\n    await client.LeaveRoom();\nawait client.JoinRoom(room, password);","typeGuard":null,"tryCatchPattern":"try { await client.JoinRoom(room, password); }\ncatch (InvalidOperationException) { /* occupied or inactive: handle in UI */ }","preventionTips":["Ensure the lounge/room transition leaves the prior room first.","Bind join-button enabled state to client.Room == null.","Await LeaveRoom fully before issuing JoinRoom."],"tags":["multiplayer","state-machine","room","invalid-operation"],"backgroundTag":null,"analyzedSha":"d9c73e12adff2feaae4a3e158d36fe5883faf6ca","analyzedAt":"2026-08-13T14:12:54.015Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}