ppy/osu · error · InvalidOperationException

Local user is not the room host.

Error message

Local user is not the room host.

What it means

AddUserPlaylistItem enforces server-side authorization: when the room's QueueMode is HostOnly, only the room host may add playlist items, otherwise it throws. This mirrors the real multiplayer server's host-only queue rule.

Source

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

            ChangeUserState(LocalUser.UserID, MultiplayerUserState.Idle);

            return Task.CompletedTask;
        }

        public override async Task AbortMatch()
        {
            ChangeUserState(api.LocalUser.Value.Id, MultiplayerUserState.Idle);
            await ((IMultiplayerClient)this).GameplayAborted(GameplayAbortReason.HostAbortedTheMatch).ConfigureAwait(false);
        }

        public async Task AddUserPlaylistItem(int userId, MultiplayerPlaylistItem item)
        {
            Debug.Assert(ServerRoom != null);
            Debug.Assert(currentItem != null);

            if (ServerRoom.Settings.QueueMode == QueueMode.HostOnly && ServerRoom.Host?.UserID != LocalUser?.UserID)
                throw new InvalidOperationException("Local user is not the room host.");

            item.OwnerID = userId;

            await addItem(item).ConfigureAwait(false);
            await updateCurrentItem(ServerRoom).ConfigureAwait(false);
            updateRoomStateIfRequired();
        }

        public override Task AddPlaylistItem(MultiplayerPlaylistItem item) => AddUserPlaylistItem(api.LocalUser.Value.OnlineID, clone(item));

        public async Task EditUserPlaylistItem(int userId, MultiplayerPlaylistItem item)
        {
            Debug.Assert(ServerRoom != null);
            Debug.Assert(currentItem != null);
            Debug.Assert(ServerAPIRoom != null);

            item.OwnerID = userId;

View on GitHub (pinned to d9c73e12ad)

Solutions

  1. Make the acting user the host before adding (e.g. TransferHost(localUserId)).
  2. Switch QueueMode to AllPlayers or PlayerOnly so any user can add.
  3. Call AddUserPlaylistItem with the host user's id instead of the non-host's.

Example fix

// before
client.ChangeSettings(queueMode: QueueMode.HostOnly);
await client.AddPlaylistItem(item); // non-host throws

// after
client.TransferHost(localUserId);
await client.AddPlaylistItem(item);
Defensive patterns

Strategy: validation

Validate before calling

if (ServerRoom.Settings.QueueMode == QueueMode.HostOnly
    && ServerRoom.Host?.UserID != LocalUser?.UserID)
{
    client.TransferHost(api.LocalUser.Value.OnlineID);
}
await client.AddPlaylistItem(item);

Prevention

When it happens

Trigger: Calling AddPlaylistItem/AddUserPlaylistItem while QueueMode == HostOnly and the local user is not ServerRoom.Host (LocalUser?.UserID != ServerRoom.Host?.UserID).

Common situations: Test sets QueueMode.HostOnly but performs the add as a non-host user; the acting user id was never made host; multi-user test where the wrong client adds.

Related errors


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