microsoft/FASTER · error · NotSupportedException
Async operations not supported over protected epoch
Error message
Async operations not supported over protected epoch
What it means
CompletePendingAsync (and other async session APIs) must not run while the current thread holds (protects) the FASTER epoch, because an await can resume on a different thread while the epoch is still held, corrupting epoch-based memory protection. FASTER throws NotSupportedException when ThisInstanceProtected() is true.
Solutions
- Do not protect the epoch (call session.UnsafeContext.Dispose()/exit protection) before issuing async operations.
- Use the synchronous CompletePending(wait: true) inside epoch-protected code.
- Restructure so async completion happens on a thread that never protects the epoch.
Example fix
// before
using (session.UnsafeContext)
{
await session.CompletePendingAsync(); // throws
}
// after
// exit protection first, then await
await session.CompletePendingAsync(); Defensive patterns
Strategy: type-guard
Validate before calling
if (fht.epoch.ThisInstanceProtected())
throw new InvalidOperationException("Exit epoch protection before CompletePendingAsync");
await session.CompletePendingAsync(); Type guard
bool EpochUnprotected(ClientSession<K, V, I, O, C, F> session) => !session.FasterKV.epoch.ThisInstanceProtected(); // via store accessor
Try / catch
try
{
await session.CompletePendingAsync();
}
catch (NotSupportedException ex) when (ex.Message.Contains("protected epoch"))
{
session.CompletePending(wait: true); // sync fallback inside protected region
} Prevention
- Never await inside UnsafeContext/epoch-protected regions or IFunctions callbacks.
- Keep a code-review rule: no 'await' between EnterProtected and ExitProtected.
- Use sync completion APIs inside protected regions.
When it happens
Trigger: Calling CompletePendingAsync (or WaitForCommitAsync, which awaits it) from inside code running under session.UnsafeContext or within a lockable/protected epoch region, e.g. inside an IFunctions callback or inside (ctx.Functions) epoch protection blocks.
Common situations: Mixing sync epoch-protected code with async APIs: awaiting inside a 'using (session.UnsafeContext)' style protected region, or issuing async calls from within RMW/Read callbacks.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Async operations not supported over protected epoch
- Make sure all async operations issued on this session are…
- Out of order message within session
- Unexpected status of SubscribeKV
- Cannot use BlittableParameterSerializer with non-blittable…
AI-assisted analysis of microsoft/FASTER@321d872eab (2026-09-15).
Data as JSON: /api/errors/36858436cceec501.
Report an issue: GitHub.
Appendix: source
Thrown at cs/src/core/ClientSession/ClientSession.cs:887
/// <inheritdoc/>
public ValueTask CompletePendingAsync(bool waitForCommit = false, CancellationToken token = default)
=> CompletePendingAsync(false, waitForCommit, token);
/// <inheritdoc/>
public async ValueTask<CompletedOutputIterator<Key, Value, Input, Output, Context>> CompletePendingWithOutputsAsync(bool waitForCommit = false, CancellationToken token = default)
{
InitializeCompletedOutputs();
await CompletePendingAsync(true, waitForCommit, token).ConfigureAwait(false);
return this.completedOutputs;
}
private async ValueTask CompletePendingAsync(bool getOutputs, bool waitForCommit = false, CancellationToken token = default)
{
token.ThrowIfCancellationRequested();
if (fht.epoch.ThisInstanceProtected())
throw new NotSupportedException("Async operations not supported over protected epoch");
// Complete all pending operations on session
await fht.CompletePendingAsync(this.FasterSession, token, getOutputs ? this.completedOutputs : null).ConfigureAwait(false);
// Wait for commit if necessary
if (waitForCommit)
await WaitForCommitAsync(token).ConfigureAwait(false);
}
/// <summary>
/// Check if at least one synchronous request is ready for CompletePending to be called on
/// Returns completed immediately if there are no outstanding synchronous requests
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
public async ValueTask ReadyToCompletePendingAsync(CancellationToken token = default)
{
token.ThrowIfCancellationRequested();View on GitHub (pinned to 321d872eab)