microsoft/garnet · error · TsavoriteException
Make sure all async operations issued on this session are aw
Error message
Make sure all async operations issued on this session are awaited and completed first
What it means
WaitForCommitAsync waits for the store's checkpoint (commit) to cover all operations completed up to the current session point. It requires that all pending async reads are drained first — if ctx.pendingReads is non-empty, there are outstanding async read operations that have not been awaited/completed, which would mean the commit point is ambiguous. The throw tells the developer to complete those reads first.
Source
Thrown at libs/storage/Tsavorite/cs/src/core/ClientSession/ClientSession.cs:408
OperationStatus status;
do
status = store.InternalModifiedBitOperation(key, out modifiedInfo, false);
while (store.HandleImmediateNonPendingRetryStatus<TInput, TOutput, TContext, TSessionFunctionsWrapper>(status, sessionFunctions));
return modifiedInfo.Modified;
}
/// <summary>
/// Wait for commit of all operations completed until the current point in session.
/// Does not itself issue checkpoint/commits.
/// </summary>
/// <returns></returns>
private async ValueTask WaitForCommitAsync<TSessionFunctionsWrapper>(TSessionFunctionsWrapper sessionFunctions, CancellationToken token = default)
where TSessionFunctionsWrapper : ISessionFunctionsWrapper<TInput, TOutput, TContext, TStoreFunctions, TAllocator>
{
token.ThrowIfCancellationRequested();
if (!ctx.pendingReads.IsEmpty)
throw new TsavoriteException("Make sure all async operations issued on this session are awaited and completed first");
// Complete all pending sync operations on session
await CompletePendingAsync(sessionFunctions, token: token).ConfigureAwait(false);
var task = store.CheckpointTask;
while (true)
{
_ = await task.WithCancellationAsync(token).ConfigureAwait(false);
Refresh(sessionFunctions);
task = store.CheckpointTask;
}
}
/// <summary>
/// Compact the log until specified address, moving active records to the tail of the log. BeginAddress is shifted, but the physical log
/// is not deleted from disk. Caller is responsible for truncating the physical log on disk by taking a checkpoint or calling Log.Truncate
/// </summary>View on GitHub (pinned to 951b0fc683)
Solutions
- Await and complete all pending async reads (via CompletePendingAsync) before calling WaitForCommitAsync.
- Track all issued async read ValueTasks and await them in a Task.WhenAll before waiting for commit.
- Use try/finally to ensure reads are drained even if an exception occurs.
Example fix
// before var readTask = session.ReadAsync(key, ref input, token); session.WaitForCommitAsync(funcs, token); // throws // after var readTask = session.ReadAsync(key, ref input, token); await readTask.ConfigureAwait(false); await session.CompletePendingAsync(funcs, token).ConfigureAwait(false); await session.WaitForCommitAsync(funcs, token).ConfigureAwait(false);
Defensive patterns
Strategy: validation
Validate before calling
if (!ctx.pendingReads.IsEmpty) throw new InvalidOperationException("Complete all pending async reads before WaitForCommitAsync."); Prevention
- Await every ReadAsync ValueTask before waiting for commit.
- Call CompletePendingAsync to drain outstanding reads before WaitForCommitAsync.
- Track issued read tasks and await them via Task.WhenAll.
When it happens
Trigger: Calling WaitForCommitAsync (directly or via CompletePendingAsync with waitForCommit=true) while the session has outstanding async reads that have not been awaited.
Common situations: Issuing ReadAsync calls and immediately calling WaitForCommitAsync without awaiting all of them; fire-and-forget async reads followed by a commit wait; an exception that skips awaiting some reads.
Related errors
- Async operations not supported over protected epoch
- EndTransactional called with locks held: {sharedLockCount} s
- Transactional method call when BeginTransactional has not be
- BeginTransactional cannot be called twice (call EndTransacti
- Can spin-wait for commit (checkpoint completion) only if wai
AI-assisted analysis of microsoft/garnet@951b0fc683 (2026-08-13).
Data as JSON: /api/errors/f00fa83729ae881c.
Report an issue: GitHub.