microsoft/FASTER · error · FasterException
Recovering to a specific version within a token is only…
Error message
Recovering to a specific version within a token is only supported for incremental snapshots
What it means
InternalRecover throws this when a non-default recoverTo (specific version within a token) is requested but the HybridLog checkpoint has no delta log (deltaLog == null), i.e. it is a full snapshot. Version-precise recovery within a token is only possible with incremental snapshots, because only delta logs record the intermediate commit points between full snapshots.
Solutions
- Take checkpoints as incremental snapshots: pass fullSnapshot: false to TakeHybridLogCheckpoint (or configure CheckpointSettings) so delta logs are retained.
- Recover to the whole token (recoverTo = -1) instead of a specific version when only full snapshots exist.
- Recover to the closest available token/version that the existing full snapshot supports.
Example fix
// before faster.Recover(indexToken, hlogToken, recoverTo: 1234); // hlog token is a full snapshot // after await faster.TakeHybridLogCheckpointAsync(fullSnapshot: false); // enable delta logs faster.Recover(indexToken, hlogToken, recoverTo: 1234);
Defensive patterns
Strategy: validation
Validate before calling
// Only request version-level recovery if the token came from an incremental snapshot
if (recoverTo != -1 && !checkpointWasIncremental(hybridLogToken))
throw new InvalidOperationException("Version recovery requires an incremental snapshot; recover to whole token instead."); Try / catch
try
{
await faster.RecoverAsync(recoverTo: version);
}
catch (FasterException ex) when (ex.Message.Contains("only supported for incremental snapshots"))
{
await faster.RecoverAsync(); // fall back to recovering the whole token
} Prevention
- Keep snapshot mode consistent between checkpointing and recovery code paths.
- Record whether each token is a full or incremental snapshot in your token metadata store.
- Use fullSnapshot: false when version-precise recovery is a requirement.
When it happens
Trigger: Calling Recover(recoverTo: someVersion) or RecoverAsync with a version argument while passing hybridLogToken taken as a full snapshot (TakeFullCheckpoint or TakeHybridLogCheckpoint with fullSnapshot: true).
Common situations: Mixing snapshot modes: team switched checkpoints to full snapshots for speed but application code still requests version-level recovery; recovering with tokens copied from another deployment that used incremental snapshots.
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
- Unable to set first valid segment to
- Unable to set last valid segment to
- Invalid version
- Unable to find valid HybridLog token
- Cannot recover from (
AI-assisted analysis of microsoft/FASTER@321d872eab (2026-09-15).
Data as JSON: /api/errors/1b4dfa6a5e025ad5.
Report an issue: GitHub.
Appendix: source
Thrown at cs/src/core/Index/Recovery/Recovery.cs:352
if (recoveredICInfo.IsDefault())
{
logger?.LogInformation("No index checkpoint found, recovering from beginning of log");
}
}
private static bool IsCompatible(in IndexRecoveryInfo indexInfo, in HybridLogRecoveryInfo recoveryInfo)
{
var l1 = indexInfo.finalLogicalAddress;
var l2 = recoveryInfo.finalLogicalAddress;
return l1 <= l2;
}
private long InternalRecover(Guid indexToken, Guid hybridLogToken, int numPagesToPreload, bool undoNextVersion, long recoverTo)
{
GetRecoveryInfo(indexToken, hybridLogToken, out HybridLogCheckpointInfo recoveredHLCInfo, out IndexCheckpointInfo recoveredICInfo);
if (recoverTo != -1 && recoveredHLCInfo.deltaLog == null)
{
throw new FasterException("Recovering to a specific version within a token is only supported for incremental snapshots");
}
return InternalRecover(recoveredICInfo, recoveredHLCInfo, numPagesToPreload, undoNextVersion, recoverTo);
}
private ValueTask<long> InternalRecoverAsync(Guid indexToken, Guid hybridLogToken, int numPagesToPreload, bool undoNextVersion, long recoverTo, CancellationToken cancellationToken)
{
GetRecoveryInfo(indexToken, hybridLogToken, out HybridLogCheckpointInfo recoveredHLCInfo, out IndexCheckpointInfo recoveredICInfo);
return InternalRecoverAsync(recoveredICInfo, recoveredHLCInfo, numPagesToPreload, undoNextVersion, recoverTo, cancellationToken);
}
private void GetRecoveryInfo(Guid indexToken, Guid hybridLogToken, out HybridLogCheckpointInfo recoveredHLCInfo, out IndexCheckpointInfo recoveredICInfo)
{
logger?.LogInformation("********* Primary Recovery Information ********");
logger?.LogInformation("Index Checkpoint: {indexToken}", indexToken);
logger?.LogInformation("HybridLog Checkpoint: {hybridLogToken}", hybridLogToken);
// Recovery appropriate context informationView on GitHub (pinned to 321d872eab)