stride3d/stride · error · TransactionException

A disposed operation cannot be rollforwarded.

Error message

A disposed operation cannot be rollforwarded.

What it means

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.

Solutions

  1. Only call Rollforward on live (non-frozen) operations; check IsFrozen first
  2. Create a new transaction/operation to re-apply committed changes
  3. Rebuild the redo stack from a fresh source after completion

Example fix

// before
transaction.Complete();
operation.Rollforward(); // throws
// after
if (!operation.IsFrozen)
    operation.Rollforward();
Defensive patterns

Strategy: type-guard

Validate before calling

if (operation.IsFrozen)
    throw new InvalidOperationException("Cannot roll forward a completed operation");

Type guard

bool CanRollforward(IOperation op) => op is Operation o && !o.IsFrozen;

Try / catch

try { operation.Rollforward(); }
catch (TransactionException ex) when (ex.Message.Contains("disposed operation cannot be rollforwarded"))
{
    logger.LogWarning("Attempted rollforward of completed operation");
}

Prevention

When it happens

Trigger: 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.

Common situations: Redo after commit without creating a new transaction, replaying stored operations that were already frozen.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/4b6453962795aca0. Report an issue: GitHub.

Appendix: source

Thrown at sources/core/Stride.Core.Design/Transactions/Operation.cs:95

    /// <inheritdoc/>
    void IOperation.Rollback()
    {
        if (IsFrozen)
            throw new TransactionException("A disposed operation cannot be rollbacked.");
        if (inProgress)
            throw new TransactionException("This operation is already in progress");

        inProgress = true;
        Rollback();
        inProgress = false;
    }

    /// <inheritdoc/>
    void IOperation.Rollforward()
    {
        if (IsFrozen)
            throw new TransactionException("A disposed operation cannot be rollforwarded.");
        if (inProgress)
            throw new TransactionException("This operation is already in progress");

        inProgress = true;
        Rollforward();
        inProgress = false;
    }
}

View on GitHub (pinned to 96fad776d2)