stride3d/stride · error · TransactionException

Unable to rollback. A transaction is in progress.

Error message

Unable to rollback. A transaction is in progress.

What it means

Rollback() cannot run while a transaction is still in progress (created but not ended); the transactionsInProgress stack must be empty because undoing history mid-transaction would corrupt the transaction state. This error is thrown when Rollback is called while transactionsInProgress.Count > 0.

Solutions

  1. Ensure EndTransaction is called (try/finally) for every open transaction before allowing rollback.
  2. Close or roll back the in-progress transaction scope explicitly before invoking Rollback.
  3. Fix exception paths that leak open transactions (wrap scopes in using/finally).
  4. Keep transactions short-lived; do not hold them open across user-driven undo commands.

Example fix

// before
using (var tx = stack.CreateTransaction())
{
    stack.Rollback(); // invalid: tx still open
}

// after
using (var tx = stack.CreateTransaction())
{
    // record operations
}
stack.Rollback(); // only after transaction ended
Defensive patterns

Strategy: validation

Validate before calling

if (transactionStack.CanRollback && !transactionStack.TransactionInProgress)
    transactionStack.Rollback();

Type guard

bool CanUndoSafely(TransactionStack stack) => stack.CanRollback && !stack.TransactionInProgress;

Try / catch

try
{
    transactionStack.Rollback();
}
catch (TransactionException ex) when (ex.Message.Contains("A transaction is in progress"))
{
    // end the open transaction before retrying
}

Prevention

When it happens

Trigger: Calling transactionStack.Rollback() between CreateTransaction/PushTransaction and the matching EndTransaction call.

Common situations: Undo triggered by UI while a batch/compound edit is still being recorded; an inner transaction leaked after an exception left EndTransaction uncalled; long-running transactions spanning user interactions.

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/f92c5601a99c925f. Report an issue: GitHub.

Appendix: source

Thrown at sources/core/Stride.Core.Design/Transactions/TransactionStack.cs:225

                {
                    foreach (var parentTransaction in transactionsInProgress.Reverse())
                        parentTransaction.Complete();
                }
            }
        }
    }

    /// <inheritdoc/>
    public void Rollback()
    {
        lock (lockObject)
        {
            if (!CanRollback)
                throw new TransactionException("Unable to rollback. This method cannot be invoked when CanRollback is false.");
            if (RollInProgress)
                throw new TransactionException("Unable to rollback. A rollback or rollforward operation is already in progress.");
            if (transactionsInProgress.Count > 0)
                throw new TransactionException("Unable to rollback. A transaction is in progress.");

            var lastTransaction = transactions[--currentPosition];
            RollInProgress = true;
            try
            {
                lastTransaction.Interface.Rollback();
            }
            finally
            {
                RollInProgress = false;
            }
            TransactionRollbacked?.Invoke(this, new TransactionEventArgs(lastTransaction));
        }
    }

    /// <inheritdoc/>
    public void Rollforward()
    {

View on GitHub (pinned to 96fad776d2)