stride3d/stride · error · TransactionException
Unable to rollforward. A rollback or rollforward operation…
Error message
Unable to rollforward. A rollback or rollforward operation is already in progress.
What it means
Rollforward() rejects re-entrant or concurrent invocation while another rollback/rollforward is running; the stack sets RollInProgress for the duration and this guard prevents the redo loop from being corrupted. This error is thrown when Rollforward is called while RollInProgress is already true.
Solutions
- Never call Rollforward/Rollback from inside transaction rollback/rollforward handlers.
- Serialize undo/redo calls onto one thread or guard them with a lock/flag.
- Suppress re-entrant notifications while a roll operation is running (guard flags in event handlers).
- Check transactionStack.RollInProgress before invoking Rollforward.
Example fix
// before
void OnTransactionRolledForward() => stack.Rollforward(); // re-entrant
// after
void OnTransactionRolledForward()
{
if (!stack.RollInProgress)
stack.Rollforward();
} Defensive patterns
Strategy: validation
Validate before calling
if (!transactionStack.RollInProgress && transactionStack.CanRollforward)
transactionStack.Rollforward(); Type guard
bool IsRollIdle(TransactionStack stack) => !stack.RollInProgress;
Try / catch
try
{
transactionStack.Rollforward();
}
catch (TransactionException ex) when (ex.Message.Contains("already in progress"))
{
// re-entrant or concurrent call; ignore or defer
} Prevention
- Never 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 Rollforward() from inside a transaction's Rollforward/Rollback handler (re-entrancy), or from another thread while a rollback/rollforward is in progress.
Common situations: Redo handlers that themselves trigger redo via property-change feedback loops; queued UI commands firing Rollforward twice; multithreaded redo calls.
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 rollback. A rollback or rollforward operation is…
- 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/ac8eaa797c5abb4e.
Report an issue: GitHub.
Appendix: source
Thrown at sources/core/Stride.Core.Design/Transactions/TransactionStack.cs:249
lastTransaction.Interface.Rollback();
}
finally
{
RollInProgress = false;
}
TransactionRollbacked?.Invoke(this, new TransactionEventArgs(lastTransaction));
}
}
/// <inheritdoc/>
public void Rollforward()
{
lock (lockObject)
{
if (!CanRollforward)
throw new TransactionException("Unable to rollforward. This method cannot be invoked when CanRollforward is false.");
if (RollInProgress)
throw new TransactionException("Unable to rollforward. 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.Rollforward();
}
finally
{
RollInProgress = false;
}
TransactionRollforwarded?.Invoke(this, new TransactionEventArgs(lastTransaction));
}
}
public void Resize(int newCapacity)View on GitHub (pinned to 96fad776d2)