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

  1. Take checkpoints as incremental snapshots: pass fullSnapshot: false to TakeHybridLogCheckpoint (or configure CheckpointSettings) so delta logs are retained.
  2. Recover to the whole token (recoverTo = -1) instead of a specific version when only full snapshots exist.
  3. 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

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


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 information

View on GitHub (pinned to 321d872eab)