{"record":{"id":"4b6453962795aca0","repo":"stride3d/stride","slug":"a-disposed-operation-cannot-be-rollforwarded","errorCode":null,"errorMessage":"A disposed operation cannot be rollforwarded.","messagePattern":"A disposed operation cannot be rollforwarded\\.","errorType":"exception","errorClass":"TransactionException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core.Design/Transactions/Operation.cs","lineNumber":95,"sourceCode":"\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();\n        inProgress = false;\n    }\n}\n","sourceCodeStart":77,"sourceCodeEnd":104,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core.Design/Transactions/Operation.cs#L77-L104","documentation":"Lifecycle guard in Operation.Rollforward: the operation is frozen (IsFrozen), meaning it was completed and its saved state was discarded; a frozen/disposed operation can no longer be rolled forward. Redoing an operation after the transaction was finalized is not allowed.","triggerScenarios":"Calling IOperation.Rollforward() on an operation after its transaction was completed/disposed (IsFrozen == true), e.g. a redo stack holding references to operations from finished transactions.","commonSituations":"Redo after commit without creating a new transaction, replaying stored operations that were already frozen.","solutions":["Only call Rollforward on live (non-frozen) operations; check IsFrozen first","Create a new transaction/operation to re-apply committed changes","Rebuild the redo stack from a fresh source after completion"],"exampleFix":"// before\ntransaction.Complete();\noperation.Rollforward(); // throws\n// after\nif (!operation.IsFrozen)\n    operation.Rollforward();","handlingStrategy":"type-guard","validationCode":"if (operation.IsFrozen)\n    throw new InvalidOperationException(\"Cannot roll forward a completed operation\");","typeGuard":"bool CanRollforward(IOperation op) => op is Operation o && !o.IsFrozen;","tryCatchPattern":"try { operation.Rollforward(); }\ncatch (TransactionException ex) when (ex.Message.Contains(\"disposed operation cannot be rollforwarded\"))\n{\n    logger.LogWarning(\"Attempted rollforward of completed operation\");\n}","preventionTips":["Only redo live operations; rebuild redo entries after completion","Check IsFrozen before Rollforward","Create a new transaction to re-apply committed changes"],"tags":["transaction","rollforward","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"}