stride3d/stride · error · TransactionException
Unable to rollback. A rollback or rollforward operation is…
Error message
Unable to rollback. A rollback or rollforward operation is already in progress.
What it means
Rollback() rejects re-entrant or concurrent invocation while another rollback/rollforward is running; the stack sets RollInProgress during the operation and this guard prevents corrupting the position while a rollback loop is active. This error is thrown when Rollback is called while RollInProgress is already true.
Solutions
- Never call Rollback/Rollforward from inside transaction rollback/rollforward handlers.
- Serialize undo/redo calls onto a single thread or use a lock/flag around stack operations.
- Suppress re-entrant notifications while a rollback is running (guard flags in event handlers).
- Check transactionStack.RollInProgress before invoking Rollback.
Example fix
// before
void OnTransactionRolledBack() => stack.Rollback(); // re-entrant
// after
void OnTransactionRolledBack()
{
if (!stack.RollInProgress)
stack.Rollback();
} Defensive patterns
Strategy: validation
Validate before calling
if (!transactionStack.RollInProgress && transactionStack.CanRollback)
transactionStack.Rollback(); Type guard
bool IsRollIdle(TransactionStack stack) => !stack.RollInProgress;
Try / catch
try
{
transactionStack.Rollback();
}
catch (TransactionException ex) when (ex.Message.Contains("already in progress"))
{
// re-entrant or concurrent call; ignore or defer
} Prevention
- Never undo/redo from inside transaction handlers.
- Use a re-entrancy guard flag in event handlers.
- Funnel all undo/redo calls through one dispatcher/thread.
When it happens
Trigger: Calling Rollback() from inside a transaction's Rollback handler (re-entrancy), or from another thread while a rollback/rollforward is in progress.
Common situations: Undo handlers that themselves trigger undo (e.g. property-change feedback loops); UI double-clicks or queued commands firing Rollback twice; multithreaded code calling Rollback concurrently.
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
- Unable to clear. A rollback or rollforward operation is in…
- Unable to rollforward. A rollback or rollforward operation…
- The transaction being completed is not that last created…
- There is no transaction in progress in the transaction…
- There is not transaction in progress in the transaction…
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/3632270048fff1e9.
Report an issue: GitHub.
Appendix: source
Thrown at sources/core/Stride.Core.Design/Transactions/TransactionStack.cs:223
// Complete parent transactions
if ((transaction.Flags & TransactionFlags.KeepParentsAlive) != 0)
{
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/>View on GitHub (pinned to 96fad776d2)