ppy/osu · error · InvalidOperationException

Invalid password.

Error message

Invalid password.

What it means

JoinRoomInternal resolves the target ServerSideRoom by id, then compares the supplied password to ServerAPIRoom.Password and throws on mismatch. This replicates the real server's password gate inside the in-process test double.

Source

Thrown at osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs:244

            var user = ServerRoom.Users.Single(u => u.UserID == userId);
            user.BeatmapAvailability = newBeatmapAvailability;

            ((IMultiplayerClient)this).UserBeatmapAvailabilityChanged(clone(userId), clone(user.BeatmapAvailability));
        }

        protected override async Task<MultiplayerRoom> JoinRoomInternal(long roomId, string? password = null)
        {
            if (RoomJoined || ServerAPIRoom != null)
                throw new InvalidOperationException("Already joined a room");

            roomId = clone(roomId);
            password = clone(password);

            ServerAPIRoom = ServerSideRooms.Single(r => r.RoomID == roomId);

            if (password != ServerAPIRoom.Password)
                throw new InvalidOperationException("Invalid password.");

            lastPlaylistItemId = ServerAPIRoom.Playlist.Max(item => item.ID);

            var localUser = new MultiplayerRoomUser(api.LocalUser.Value.Id)
            {
                User = api.LocalUser.Value
            };

            ServerRoom = new MultiplayerRoom(roomId)
            {
                Settings =
                {
                    Name = ServerAPIRoom.Name,
                    MatchType = ServerAPIRoom.Type,
                    Password = password ?? string.Empty,
                    QueueMode = ServerAPIRoom.QueueMode,
                    AutoStartDuration = ServerAPIRoom.AutoStartDuration,
                    MaxParticipants = ServerAPIRoom.MaxParticipants,

View on GitHub (pinned to d9c73e12ad)

Solutions

  1. Pass the room's actual password: await client.JoinRoom(room.RoomID.Value, room.Password).
  2. If the test does not need password protection, create the room with a null/empty password.
  3. Verify the password string equals ServerSideRooms.Single(r => r.RoomID == id).Password before joining.

Example fix

// before
await client.JoinRoom(room.RoomID.Value);

// after
await client.JoinRoom(room.RoomID.Value, room.Password);
Defensive patterns

Strategy: validation

Validate before calling

string? pwd = room.Password;
if (pwd != ServerSideRooms.Single(r => r.RoomID == room.RoomID).Password)
    throw new InvalidOperationException("password mismatch pre-check");
await client.JoinRoom(room.RoomID.Value, pwd);

Prevention

When it happens

Trigger: Joining a password-protected room with a null or incorrect password; the room was created with a password but the join call omits it.

Common situations: Test creates a room with Password set but joins without it; a cloned room object lost its password; password casing/whitespace mismatch.

Related errors


AI-assisted analysis of ppy/osu@d9c73e12ad (2026-08-13). Data as JSON: /api/errors/544fe0b1d99aa97b. Report an issue: GitHub.