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
- Pass the room's actual password: await client.JoinRoom(room.RoomID.Value, room.Password).
- If the test does not need password protection, create the room with a null/empty password.
- 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
- Always pass room.Password into JoinRoom rather than a literal.
- If the test does not need a password, create the room without one.
- Keep the password on the same Room object you join with to avoid drift.
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
- Accessing the client-side API room via {nameof(TestMultiplay
- Accessing the client-side room via {nameof(TestMultiplayerCl
- Already joined a room
- Local user is not the room host.
- Attempted to change an item that doesn't exist.
AI-assisted analysis of ppy/osu@d9c73e12ad (2026-08-13).
Data as JSON: /api/errors/544fe0b1d99aa97b.
Report an issue: GitHub.