stride3d/stride · error · TransactionException
This operation is already in progress
Error message
This operation is already in progress
What it means
Reentrancy guard in Operation.Rollback: the operation is already mid-rollback (the inProgress flag is set), meaning Rollback was called recursively or concurrently on the same operation. Transaction operations are not reentrant to keep undo state consistent.
Solutions
- Avoid re-entrant Rollback/Rollforward calls from within rollback handlers
- Serialize access to the operation with a lock if used from multiple threads
- Wait for the in-progress operation to finish before issuing another one
Example fix
// before (re-entrant from handler)
void OnOperationEvent() => operation.Rollback(); // may recurse
// after
lock (operationLock)
{
if (!inRollback) operation.Rollback();
} Defensive patterns
Strategy: retry
Validate before calling
lock (operationLock)
{
if (operationInProgress) return; // or queue the request
} Type guard
bool IsOperationIdle(Operation o) => !o.IsFrozen; // plus external in-progress tracking
Try / catch
try { operation.Rollback(); }
catch (TransactionException ex) when (ex.Message == "This operation is already in progress")
{
// retry after the current rollback finishes, or queue
} Prevention
- Never call Rollback re-entrantly from rollback event handlers
- Synchronize multi-threaded operation access with a lock
- Queue undo requests instead of issuing them concurrently
When it happens
Trigger: Calling IOperation.Rollback() recursively or concurrently while a prior Rollback()/Rollforward() call on the same operation has not returned — typically via re-entrancy from events raised during rollback.
Common situations: Rollback handlers that re-enter the transaction API, multi-threaded access to a shared operation without synchronization.
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
- A disposed operation cannot be rollbacked.
- Unable to create a transaction. A rollback or rollforward…
- 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.
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/897983406dab12e7.
Report an issue: GitHub.
Appendix: source
Thrown at sources/core/Stride.Core.Design/Transactions/Operation.cs:84
}
/// <inheritdoc/>
void IOperation.Freeze()
{
if (IsFrozen)
throw new TransactionException("This operation is already frozen.");
FreezeContent();
IsFrozen = true;
}
/// <inheritdoc/>
void IOperation.Rollback()
{
if (IsFrozen)
throw new TransactionException("A disposed operation cannot be rollbacked.");
if (inProgress)
throw new TransactionException("This operation is already in progress");
inProgress = true;
Rollback();
inProgress = false;
}
/// <inheritdoc/>
void IOperation.Rollforward()
{
if (IsFrozen)
throw new TransactionException("A disposed operation cannot be rollforwarded.");
if (inProgress)
throw new TransactionException("This operation is already in progress");
inProgress = true;
Rollforward();
inProgress = false;
}View on GitHub (pinned to 96fad776d2)