ppy/osu · error · InvalidOperationException
The room's current item cannot be removed.
Error message
The room's current item cannot be removed.
What it means
RemoveUserPlaylistItem protects the currently-active playlist item (currentItem, i.e. ServerRoom.Playlist[currentIndex]) from removal to keep room state consistent while a beatmap is in play. Removing it throws.
Source
Thrown at osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs:596
ServerAPIRoom.Playlist = ServerAPIRoom.Playlist.Select((pi, i) => pi.ID == item.ID ? new PlaylistItem(item) : ServerAPIRoom.Playlist[i]).ToArray();
await ((IMultiplayerClient)this).PlaylistItemChanged(clone(item)).ConfigureAwait(false);
}
public override Task EditPlaylistItem(MultiplayerPlaylistItem item) => EditUserPlaylistItem(api.LocalUser.Value.OnlineID, clone(item));
public async Task RemoveUserPlaylistItem(int userId, long playlistItemId)
{
Debug.Assert(ServerRoom != null);
Debug.Assert(ServerAPIRoom != null);
var item = ServerRoom.Playlist.FirstOrDefault(i => i.ID == playlistItemId);
if (item == null)
throw new InvalidOperationException("Item does not exist in the room.");
if (item.Equals(currentItem))
throw new InvalidOperationException("The room's current item cannot be removed.");
if (item.OwnerID != userId)
throw new InvalidOperationException("Attempted to remove an item which is not owned by the user.");
if (item.Expired)
throw new InvalidOperationException("Attempted to remove an item which has already been played.");
ServerRoom.Playlist.Remove(item);
ServerAPIRoom.Playlist = ServerAPIRoom.Playlist.Where(i => i.ID != item.ID).ToArray();
await ((IMultiplayerClient)this).PlaylistItemRemoved(clone(playlistItemId)).ConfigureAwait(false);
await updateCurrentItem(ServerRoom).ConfigureAwait(false);
updateRoomStateIfRequired();
}
public override Task RemovePlaylistItem(long playlistItemId) => RemoveUserPlaylistItem(api.LocalUser.Value.OnlineID, clone(playlistItemId));
public override Task VoteToSkipIntro()
View on GitHub (pinned to d9c73e12ad)
Solutions
- Remove a different (non-current) playlist item.
- Advance the room past the item (finish/advance the match so currentItem changes) before removing it.
- If clearing the playlist, expire/skip the current item first via the normal flow.
Example fix
// before await client.RemovePlaylistItem(currentItem.ID.Value); // throws // after // remove a queued (non-current) item instead: await client.RemovePlaylistItem(ServerRoom.Playlist.First(i => i.ID != currentItem.ID && !i.Expired).ID);
Defensive patterns
Strategy: validation
Validate before calling
if (playlistItemId == currentItem?.ID)
throw new InvalidOperationException("cannot remove the active item");
await client.RemovePlaylistItem(playlistItemId); Prevention
- Never remove the currentItem; advance the match first if you must.
- Pick removal candidates where i.ID != currentItem.ID.
- Centralize removal behind a helper that skips the current item.
When it happens
Trigger: Calling RemovePlaylistItem with the ID of the item currently being played (item.Equals(currentItem) is true).
Common situations: Test tries to remove the item that the room is actively on; currentItem pointer was not advanced before removal.
Related errors
- Attempted to change an item which has already been played.
- Attempted to remove an item which has already been played.
- Attempted to change an item that doesn't exist.
- Item does not exist in the room.
- Accessing the client-side API room via {nameof(TestMultiplay
AI-assisted analysis of ppy/osu@d9c73e12ad (2026-08-13).
Data as JSON: /api/errors/1c7538d1cb8dc90b.
Report an issue: GitHub.