ppy/osu · error · InvalidOperationException

Item does not exist in the room.

Error message

Item does not exist in the room.

What it means

RemoveUserPlaylistItem throws when no playlist item matches the given playlistItemId, mirroring the server's removal precondition. The lookup uses FirstOrDefault on ServerRoom.Playlist.

Source

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

            item.PlaylistOrder = existingItem.PlaylistOrder;

            ServerRoom.Playlist[ServerRoom.Playlist.IndexOf(existingItem)] = item;
            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();
        }

View on GitHub (pinned to d9c73e12ad)

Solutions

  1. Pass an ID known to exist in ServerRoom.Playlist.
  2. Re-query ServerRoom.Playlist for a valid ID before removing.
  3. Guard against double-removal by checking existence first.

Example fix

// before
await client.RemovePlaylistItem(999); // not present

// after
long id = client.ServerRoom.Playlist.First(i => !i.Expired && i.ID != currentItem?.ID).ID;
await client.RemovePlaylistItem(id);
Defensive patterns

Strategy: validation

Validate before calling

if (!ServerRoom.Playlist.Any(i => i.ID == playlistItemId))
    throw new InvalidOperationException($"no playlist item {playlistItemId}");
await client.RemovePlaylistItem(playlistItemId);

Prevention

When it happens

Trigger: Calling RemovePlaylistItem/RemoveUserPlaylistItem with an ID not present in ServerRoom.Playlist.

Common situations: Removing an item twice; removing by a stale or cloned ID; the item was already removed by another user/step.

Related errors


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