{"record":{"id":"a45a016d270fa1cd","repo":"stride3d/stride","slug":"move-is-not-supported-by-the-undo-stack","errorCode":null,"errorMessage":"Move is not supported by the undo stack.","messagePattern":"Move is not supported by the undo stack\\.","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"sources/presentation/Stride.Core.Presentation/Dirtiables/CollectionChangeOperation.cs","lineNumber":114,"sourceCode":"                ActionToUndo = NotifyCollectionChangedAction.Add;\n                foreach (var item in items)\n                {\n                    list.Insert(index + i, item);\n                    ++i;\n                }\n                break;\n            case NotifyCollectionChangedAction.Replace:\n                var replacedItems = new List<object>();\n                foreach (var item in items)\n                {\n                    replacedItems.Add(list[index + i]);\n                    list[index + i] = item;\n                    ++i;\n                }\n                items = replacedItems;\n                break;\n            case NotifyCollectionChangedAction.Move:\n                throw new NotSupportedException(\"Move is not supported by the undo stack.\");\n            case NotifyCollectionChangedAction.Reset:\n                throw new NotSupportedException(\"Reset is not supported by the undo stack.\");\n        }\n    }\n\n    /// <inheritdoc/>\n    protected override void Redo()\n    {\n        // Once we have un-done, the previous value is updated so Redo is just Undoing the Undo\n        Undo();\n    }\n}\n","sourceCodeStart":96,"sourceCodeEnd":127,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/presentation/Stride.Core.Presentation/Dirtiables/CollectionChangeOperation.cs#L96-L127","documentation":"When undoing (or redoing the inverse of) a recorded change, CollectionChangeOperation.Undo handles Add/Remove/Replace but throws NotSupportedException for Move and Reset actions — these were never intended to be recorded by the undo stack.","triggerScenarios":"An undo/redo pass encounters a recorded operation whose ActionToUndo is Move (or Reset), i.e. the operation was created from args with those actions before reaching Undo.","commonSituations":"Undoing after a drag-reorder (Move) on a tracked list; mixing collections that emit Move/Reset events into an undo-tracked session.","solutions":["Avoid operations that raise Move on undo-tracked lists; express moves as Remove+Add","Ensure only Add/Remove/Replace actions get recorded into CollectionChangeOperation","Wrap Undo in try-catch for NotSupportedException and skip/invalidate the operation"],"exampleFix":"// before\nlist.Move(3, 0); // Move recorded, Undo throws\n// after\nvar item = list[3];\nlist.RemoveAt(3);\nlist.Insert(0, item); // Remove + Add, undoable","handlingStrategy":"try-catch","validationCode":"if (e.Action is NotifyCollectionChangedAction.Move or NotifyCollectionChangedAction.Reset) return; // don't record","typeGuard":"bool IsUndoRecordable(NotifyCollectionChangedAction a) => a is not (NotifyCollectionChangedAction.Move or NotifyCollectionChangedAction.Reset);","tryCatchPattern":"try { operation.Undo(); } catch (NotSupportedException) { undoStack.Clear(); /* history invalidated */ }","preventionTips":["Express moves as Remove+Insert","Only record Add/Remove/Replace into the undo stack","Clear history rather than undoing unsupported operations"],"tags":["csharp","undo","collections"],"backgroundTag":"unsupported-operation","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}