{"record":{"id":"991955c2f6c340b6","repo":"stride3d/stride","slug":"a-disposed-operation-cannot-be-rollbacked","errorCode":null,"errorMessage":"A disposed operation cannot be rollbacked.","messagePattern":"A disposed operation cannot be rollbacked\\.","errorType":"exception","errorClass":"TransactionException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core.Design/Transactions/Operation.cs","lineNumber":82,"sourceCode":"    {\n        return false;\n    }\n\n    /// <inheritdoc/>\n    void IOperation.Freeze()\n    {\n        if (IsFrozen)\n            throw new TransactionException(\"This operation is already frozen.\");\n\n        FreezeContent();\n        IsFrozen = true;\n    }\n\n    /// <inheritdoc/>\n    void IOperation.Rollback()\n    {\n        if (IsFrozen)\n            throw new TransactionException(\"A disposed operation cannot be rollbacked.\");\n        if (inProgress)\n            throw new TransactionException(\"This operation is already in progress\");\n\n        inProgress = true;\n        Rollback();\n        inProgress = false;\n    }\n\n    /// <inheritdoc/>\n    void IOperation.Rollforward()\n    {\n        if (IsFrozen)\n            throw new TransactionException(\"A disposed operation cannot be rollforwarded.\");\n        if (inProgress)\n            throw new TransactionException(\"This operation is already in progress\");\n\n        inProgress = true;\n        Rollforward();","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core.Design/Transactions/Operation.cs#L64-L100","documentation":"Thrown by IOperation.Rollback when the operation is frozen (the flag the library sets on completion/dispose, treated here as 'disposed'). A finalized operation can no longer undo its changes, so rolling it back is rejected.","triggerScenarios":"Calling IOperation.Rollback() on an operation after its transaction was completed/disposed (IsFrozen == true), e.g. keeping a reference to an operation and attempting an undo after transaction completion.","commonSituations":"Undo stacks retaining stale operations after commit, rollback triggered from an event handler after Dispose, reusing completed transactions.","solutions":["Do not roll back operations from completed transactions; capture the rollback need before Complete()","Check the operation/transaction state before invoking Rollback","Create a new compensating transaction to undo committed work"],"exampleFix":"// before\ntransaction.Complete();\noperation.Rollback(); // throws\n// after\nif (!operation.IsFrozen)\n    operation.Rollback();","handlingStrategy":"type-guard","validationCode":"if (operation.IsFrozen)\n    throw new InvalidOperationException(\"Cannot roll back a completed operation\");","typeGuard":"bool CanRollback(IOperation op) => op is Operation o && !o.IsFrozen;","tryCatchPattern":"try { operation.Rollback(); }\ncatch (TransactionException ex) when (ex.Message.Contains(\"disposed operation cannot be rollbacked\"))\n{\n    logger.LogWarning(\"Attempted rollback of completed operation\");\n}","preventionTips":["Do not keep operation references after transaction completion","Create compensating transactions instead of rolling back committed work","Check IsFrozen before any undo call"],"tags":["transaction","rollback","invalid-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}