microsoft/FASTER · error · FasterException
Cannot use GrowIndex when using non-async sessions
Error message
Cannot use GrowIndex when using non-async sessions
What it means
GrowIndex resizes the hash index via a state machine that must not run on an epoch-protected thread; otherwise the epoch system cannot advance threads during the resize. If the current thread holds epoch protection (non-async/blocking session usage), the call throws instead of proceeding.
Solutions
- Call GrowIndex from a context without active epoch protection (e.g., main async session loop, separate task)
- Migrate to async sessions and check GrowIndexAsync, which manages epoch protection correctly
- Restructure so index growth is triggered by background maintenance code rather than inline request handling
Example fix
// before: called while epoch protected fasterKV.epoch.Resume(); // user-managed protection fasterKV.GrowIndex(); // throws if ThisInstanceProtected // after: call from unprotected context bool grew = fasterKV.GrowIndex(); // ensure caller thread is NOT epoch-protected
Defensive patterns
Strategy: try-catch
Validate before calling
null
Try / catch
try { fasterKV.GrowIndex(); }
catch (FasterException ex) when (ex.Message.Contains("GrowIndex when using non-async sessions"))
{
// defer growth to a background task without epoch protection
await Task.Run(() => fasterKV.GrowIndex());
} Prevention
- Trigger index growth from background maintenance code, not from inside request/session callbacks
- Avoid manually managing epoch protection around index operations
- Prefer async sessions and GrowIndexAsync where available
When it happens
Trigger: Calling GrowIndex from a thread that currently has epoch protection active (e.g., inside a synchronous session operation, within epoch-protected regions, or a caller that manually entered epoch protection).
Common situations: Synchronous (non-async) sessions trying to grow the index inline; invoking GrowIndex from inside upsert/read callbacks or epoch-protected test harness code.
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 CompleteCheckpointAsync when using non-async…
- Async operations not supported over protected epoch
- Async operations not supported over protected epoch
- Make sure all async operations issued on this session are…
- unsafe to execute a state machine blockingly when under…
AI-assisted analysis of microsoft/FASTER@321d872eab (2026-09-15).
Data as JSON: /api/errors/43bd17ade33e7460.
Report an issue: GitHub.
Appendix: source
Thrown at cs/src/core/Index/FASTER/FASTER.cs:727
internalStatus = InternalDelete(ref key, keyHash, ref context, ref pcontext, fasterSession, serialNo);
while (HandleImmediateRetryStatus(internalStatus, fasterSession, ref pcontext));
var status = HandleOperationStatus(fasterSession.Ctx, ref pcontext, internalStatus);
Debug.Assert(serialNo >= fasterSession.Ctx.serialNum, "Operation serial numbers must be non-decreasing");
fasterSession.Ctx.serialNum = serialNo;
return status;
}
/// <summary>
/// Grow the hash index by a factor of two. Make sure to take a full checkpoint
/// after growth, for persistence.
/// </summary>
/// <returns>Whether the grow completed</returns>
public bool GrowIndex()
{
if (epoch.ThisInstanceProtected())
throw new FasterException("Cannot use GrowIndex when using non-async sessions");
if (!StartStateMachine(new IndexResizeStateMachine())) return false;
epoch.Resume();
try
{
while (true)
{
SystemState _systemState = SystemState.Copy(ref systemState);
if (_systemState.Phase == Phase.PREPARE_GROW)
ThreadStateMachineStep<Empty, Empty, Empty, NullFasterSession>(null, NullFasterSession.Instance, default);
else if (_systemState.Phase == Phase.IN_PROGRESS_GROW)
SplitBuckets(0);
else if (_systemState.Phase == Phase.REST)
break;
epoch.ProtectAndDrain();
Thread.Yield();View on GitHub (pinned to 321d872eab)