microsoft/FASTER · error · FasterException
Cannot use CompleteCheckpointAsync when using non-async…
Error message
Cannot use CompleteCheckpointAsync when using non-async sessions
What it means
CompleteCheckpointAsync must run inside an async (epoch-unprotected) context. If the calling thread currently holds the epoch protection (ThisInstanceProtected() is true), it means the caller is using a synchronous/non-async session and blocking-epoch semantics, so the async wait would deadlock or violate epoch discipline; the library throws instead.
Solutions
- Use the async checkpoint APIs end-to-end: TakeFullCheckpointAsync/CompleteCheckpointAsync from a non-epoch-protected context
- If using blocking checkpoints, rely on their own completion semantics instead of calling CompleteCheckpointAsync
- Move the CompleteCheckpointAsync call out of epoch-protected regions and session callbacks onto an independent async continuation
Example fix
// before: same thread still epoch-protected fasterKV.TakeFullCheckpoint(out token); // blocking, protected await fasterKV.CompleteCheckpointAsync(); // throws // after (long token, _) = await fasterKV.TakeFullCheckpointAsync(); // async path handles completion
Defensive patterns
Strategy: try-catch
Validate before calling
// Only call CompleteCheckpointAsync if the current thread is NOT epoch-protected
if (fasterKV is not null /* and caller is on async session flow, not inside callbacks */)
{
// proceed with async completion only from async session paths
} Try / catch
try { await fasterKV.CompleteCheckpointAsync(); }
catch (FasterException ex) when (ex.Message.Contains("CompleteCheckpointAsync when using non-async sessions"))
{
// you are on a blocking/protected path: switch to the async checkpoint API
} Prevention
- Never mix blocking checkpoint calls with CompleteCheckpointAsync on the same thread
- Call checkpoint completion only from async session flows, never inside epoch-protected regions or session callbacks
- Use TakeFullCheckpointAsync/TakeHybridLogCheckpointAsync, which handle completion internally
When it happens
Trigger: Calling CompleteCheckpointAsync from code that has entered epoch protection (e.g., inside a session's synchronous callback, insideEpochProtected region, or after manually calling epoch.Resume()/Protect on the same thread), instead of completing the checkpoint on a separate async flow.
Common situations: Mixing blocking (synchronous) session APIs like TakeFullCheckpoint followed by CompleteCheckpointAsync on the same protected thread; calling CompleteCheckpointAsync inside IFasterStateMachine callbacks; wrappers that call async APIs while holding epoch protection.
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
- Cannot use GrowIndex when using non-async sessions
- Make sure all async operations issued on this session are…
- Unable to set first valid segment to
- Unable to set last valid segment to
- Async operations not supported over protected epoch
AI-assisted analysis of microsoft/FASTER@321d872eab (2026-09-15).
Data as JSON: /api/errors/050aff2a8059cd08.
Report an issue: GitHub.
Appendix: source
Thrown at cs/src/core/Index/FASTER/FASTER.cs:542
/// Asynchronously recover from specific index and log token (blocking operation)
/// </summary>
/// <param name="indexCheckpointToken"></param>
/// <param name="hybridLogCheckpointToken"></param>
/// <param name="numPagesToPreload">Number of pages to preload into memory after recovery</param>
/// <param name="undoNextVersion">Whether records with versions beyond checkpoint version need to be undone (and invalidated on log)</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>Version we actually recovered to</returns>
public ValueTask<long> RecoverAsync(Guid indexCheckpointToken, Guid hybridLogCheckpointToken, int numPagesToPreload = -1, bool undoNextVersion = true, CancellationToken cancellationToken = default)
=> InternalRecoverAsync(indexCheckpointToken, hybridLogCheckpointToken, numPagesToPreload, undoNextVersion, -1, cancellationToken);
/// <summary>
/// Wait for ongoing checkpoint to complete
/// </summary>
/// <returns></returns>
public async ValueTask CompleteCheckpointAsync(CancellationToken token = default)
{
if (epoch.ThisInstanceProtected())
throw new FasterException("Cannot use CompleteCheckpointAsync when using non-async sessions");
token.ThrowIfCancellationRequested();
while (true)
{
var systemState = this.systemState;
if (systemState.Phase == Phase.REST || systemState.Phase == Phase.PREPARE_GROW ||
systemState.Phase == Phase.IN_PROGRESS_GROW)
return;
List<ValueTask> valueTasks = new();
try
{
epoch.Resume();
ThreadStateMachineStep<Empty, Empty, Empty, NullFasterSession>(null, NullFasterSession.Instance, valueTasks, token);
}
catch (Exception)View on GitHub (pinned to 321d872eab)