ppy/osu · error · InvalidOperationException

Attempted to change an item that doesn't exist.

Error message

Attempted to change an item that doesn't exist.

What it means

EditUserPlaylistItem looks up the target by item.ID in ServerRoom.Playlist (SingleOrDefault) and throws if nothing matches, reproducing the server's 'item must exist before you can edit it' precondition.

Source

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

            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;

            var existingItem = ServerRoom.Playlist.SingleOrDefault(i => i.ID == item.ID);

            if (existingItem == null)
                throw new InvalidOperationException("Attempted to change an item that doesn't exist.");

            if (existingItem.OwnerID != userId && ServerRoom.Host?.UserID != LocalUser?.UserID)
                throw new InvalidOperationException("Attempted to change an item which is not owned by the user.");

            if (existingItem.Expired)
                throw new InvalidOperationException("Attempted to change an item which has already been played.");

            // Ensure the playlist order doesn't change.
            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));

View on GitHub (pinned to d9c73e12ad)

Solutions

  1. Set item.ID to an existing ServerRoom.Playlist entry's ID before editing.
  2. Re-read the current playlist from ServerRoom.Playlist to get a valid ID.
  3. If the item should not exist yet, AddPlaylistItem it first instead of editing.

Example fix

// before
item.ID = 999; // not in playlist
await client.EditPlaylistItem(item);

// after
item.ID = client.ServerRoom.Playlist.First(i => !i.Expired).ID;
await client.EditPlaylistItem(item);
Defensive patterns

Strategy: validation

Validate before calling

var existing = ServerRoom.Playlist.SingleOrDefault(i => i.ID == item.ID);
if (existing == null)
    throw new InvalidOperationException($"no playlist item {item.ID} to edit");
await client.EditPlaylistItem(item);

Prevention

When it happens

Trigger: Calling EditPlaylistItem/EditUserPlaylistItem with an ID that is not present in ServerRoom.Playlist (stale, removed, or never-added).

Common situations: Editing a cloned item whose ID no longer exists; the item was already removed by another step; using an arbitrary/hardcoded ID.

Related errors


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