stride3d/stride · error · TransactionException

Unable to create a transaction. A rollback or rollforward…

Error message

Unable to create a transaction. A rollback or rollforward operation is in progress.

What it means

Thrown by TransactionStack.CreateTransaction when the stack is currently executing a rollback or rollforward. New transactions cannot be created while the undo/redo machinery is unwinding/applying operations, as that would corrupt the stack.

Solutions

  1. Defer transaction creation until the rollback/rollforward finishes (check RollInProgress first and retry)
  2. Do not create transactions from handlers invoked during undo/redo; queue the work and apply it afterward
  3. Synchronize transaction creation through a single dispatcher/thread

Example fix

// before
stack.Rollback(); // triggers events
var t = stack.CreateTransaction(); // throws from event handler
// after
ITransaction t = null;
if (!stack.RollInProgress)
    t = stack.CreateTransaction();
else
    pendingWork.Enqueue(() => stack.CreateTransaction());
Defensive patterns

Strategy: validation

Validate before calling

if (stack.RollInProgress)
    throw new InvalidOperationException("Stack is rolling; defer transaction creation");
var t = stack.CreateTransaction();

Type guard

bool CanCreateTransaction(TransactionStack s) => !s.RollInProgress;

Try / catch

try { return stack.CreateTransaction(); }
catch (TransactionException ex) when (ex.Message.Contains("rollback or rollforward operation is in progress"))
{
    pendingTransactions.Enqueue(flags);
    return null;
}

Prevention

When it happens

Trigger: Calling CreateTransaction from another thread (or re-entrantly from a rollback/rollforward handler) while TransactionStack.RollInProgress is true — e.g. transactions spawned from events fired during an undo/redo.

Common situations: UI event handlers firing during an undo operation, background tasks creating transactions concurrently with a rollback, re-entrant edits inside transaction completion events.

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

Appendix: source

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

    /// <inheritdoc/>
    public event EventHandler<TransactionEventArgs>? TransactionRollbacked;

    /// <inheritdoc/>
    public event EventHandler<TransactionEventArgs>? TransactionRollforwarded;

    /// <inheritdoc/>
    public event EventHandler<TransactionsDiscardedEventArgs>? TransactionDiscarded;

    /// <inheritdoc/>
    public event EventHandler<EventArgs>? Cleared;

    /// <inheritdoc/>
    public ITransaction CreateTransaction(TransactionFlags flags = TransactionFlags.None)
    {
        lock (lockObject)
        {
            if (RollInProgress)
                throw new TransactionException("Unable to create a transaction. A rollback or rollforward operation is in progress.");

            var transaction = new Transaction(this, flags);
            if ((flags & TransactionFlags.KeepParentsAlive) != 0)
            {
                foreach (var parentTransaction in transactionsInProgress)
                    parentTransaction.AddReference();
            }

            transactionsInProgress.Push(transaction);
            TransactionInProgress = true;
            return transaction;
        }
    }

    /// <inheritdoc/>
    public void PushOperation(Operation operation)
    {
        lock (lockObject)

View on GitHub (pinned to 96fad776d2)