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
- Defer transaction creation until the rollback/rollforward finishes (check RollInProgress first and retry)
- Do not create transactions from handlers invoked during undo/redo; queue the work and apply it afterward
- 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
- Check RollInProgress before creating transactions
- Never create transactions from undo/redo event handlers
- Marshal transaction creation through one thread/dispatcher and queue during rolls
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
- This operation is already in progress
- Aynchronous lock can only be acquired from a micro-thread…
- Trying to enter a lock that has already been entered
- Trying to lock while another thread owns the lock.
- This operation is already frozen.
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)