{"record":{"id":"d65f6e60fc271c4c","repo":"ppy/osu","slug":"attempted-to-change-an-item-which-has-already-been","errorCode":null,"errorMessage":"Attempted to change an item which has already been played.","messagePattern":"Attempted to change an item which has already been played\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs","lineNumber":572,"sourceCode":"\r\n        public async Task EditUserPlaylistItem(int userId, MultiplayerPlaylistItem item)\r\n        {\r\n            Debug.Assert(ServerRoom != null);\r\n            Debug.Assert(currentItem != null);\r\n            Debug.Assert(ServerAPIRoom != null);\r\n\r\n            item.OwnerID = userId;\r\n\r\n            var existingItem = ServerRoom.Playlist.SingleOrDefault(i => i.ID == item.ID);\r\n\r\n            if (existingItem == null)\r\n                throw new InvalidOperationException(\"Attempted to change an item that doesn't exist.\");\r\n\r\n            if (existingItem.OwnerID != userId && ServerRoom.Host?.UserID != LocalUser?.UserID)\r\n                throw new InvalidOperationException(\"Attempted to change an item which is not owned by the user.\");\r\n\r\n            if (existingItem.Expired)\r\n                throw new InvalidOperationException(\"Attempted to change an item which has already been played.\");\r\n\r\n            // Ensure the playlist order doesn't change.\r\n            item.PlaylistOrder = existingItem.PlaylistOrder;\r\n\r\n            ServerRoom.Playlist[ServerRoom.Playlist.IndexOf(existingItem)] = item;\r\n            ServerAPIRoom.Playlist = ServerAPIRoom.Playlist.Select((pi, i) => pi.ID == item.ID ? new PlaylistItem(item) : ServerAPIRoom.Playlist[i]).ToArray();\r\n\r\n            await ((IMultiplayerClient)this).PlaylistItemChanged(clone(item)).ConfigureAwait(false);\r\n        }\r\n\r\n        public override Task EditPlaylistItem(MultiplayerPlaylistItem item) => EditUserPlaylistItem(api.LocalUser.Value.OnlineID, clone(item));\r\n\r\n        public async Task RemoveUserPlaylistItem(int userId, long playlistItemId)\r\n        {\r\n            Debug.Assert(ServerRoom != null);\r\n            Debug.Assert(ServerAPIRoom != null);\r\n\r\n            var item = ServerRoom.Playlist.FirstOrDefault(i => i.ID == playlistItemId);\r","sourceCodeStart":554,"sourceCodeEnd":590,"githubUrl":"https://github.com/ppy/osu/blob/d9c73e12adff2feaae4a3e158d36fe5883faf6ca/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs#L554-L590","documentation":"EditUserPlaylistItem refuses to modify items whose Expired flag is true. The server marks a playlist item Expired once it has been played, and expired items are immutable.","triggerScenarios":"Editing an item that has already been played through (existingItem.Expired == true).","commonSituations":"Test advanced the playlist past an item (finish/start match) then tried to edit it; editing the currentItem after it expired; reusing a stale item reference.","solutions":["Add a fresh playlist item and edit that instead of an expired one.","Edit the item before it gets played (before updateCurrentItem expires it).","If you need to change a played item, remove-and-readd is not possible for expired items either — add a new item with the desired values."],"exampleFix":"// before (item already played)\nawait client.EditPlaylistItem(expiredItem);\n\n// after\nawait client.AddPlaylistItem(new MultiplayerPlaylistItem(newBeatmap));","handlingStrategy":"validation","validationCode":"var existing = ServerRoom.Playlist.Single(i => i.ID == item.ID);\nif (existing.Expired)\n    throw new InvalidOperationException(\"item already played; add a new one\");\nawait client.EditPlaylistItem(item);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Edit items before they are played (before they expire).","Filter ServerRoom.Playlist to non-expired items before editing.","Re-add a fresh item rather than trying to revive an expired one."],"tags":["test-infra","multiplayer","playlist","lifecycle"],"backgroundTag":null,"analyzedSha":"d9c73e12adff2feaae4a3e158d36fe5883faf6ca","analyzedAt":"2026-08-13T14:12:54.015Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}