microsoft/garnet · critical · TsavoriteException
Unable to set first valid segment to {firstValidSegment}, fi
Error message
Unable to set first valid segment to {firstValidSegment}, first available segment on disk is {firstAvailSegment} What it means
Thrown by VerifyRecoveryInfo during recovery when the checkpoint's beginAddress maps to a segment (firstValidSegment) that is earlier than the first segment still present on the log device (device.StartSegment). In other words, recovery needs a disk segment that has already been deleted/truncated. The store cannot replay records that no longer exist on disk.
Source
Thrown at libs/storage/Tsavorite/cs/src/core/Allocator/AllocatorBase.cs:729
var firstAvailSegment = device.StartSegment;
var lastAvailSegment = device.EndSegment;
if (FlushedUntilAddress > GetFirstValidLogicalAddressOnPage(0))
{
var flushedUntilAddress = FlushedUntilAddress;
int currTailSegment = (int)GetSegment(flushedUntilAddress);
if (GetOffsetOnSegment(flushedUntilAddress) == 0)
currTailSegment--;
if (currTailSegment > lastAvailSegment)
lastAvailSegment = currTailSegment;
}
logger?.LogInformation("Available segment range on device: [{firstAvailSegment}--{lastAvailSegment}]", firstAvailSegment, lastAvailSegment);
if (firstValidSegment < firstAvailSegment)
throw new TsavoriteException($"Unable to set first valid segment to {firstValidSegment}, first available segment on disk is {firstAvailSegment}");
if (lastAvailSegment >= 0 && lastValidSegment > lastAvailSegment)
throw new TsavoriteException($"Unable to set last valid segment to {lastValidSegment}, last available segment on disk is {lastAvailSegment}");
if (trimLog)
{
logger?.LogInformation("Trimming disk segments until (not including) {firstSegment}", firstValidSegment);
var toAddress = GetStartLogicalAddressOfSegment(firstValidSegment);
TruncateUntilAddressBlocking(toAddress);
if (storeFunctions.CallOnTruncate)
storeFunctions.OnTruncate(toAddress);
for (int s = lastValidSegment + 1; s <= lastAvailSegment; s++)
{
logger?.LogInformation("Trimming tail segment {s} on disk", s);
RemoveSegment(s);
}
}View on GitHub (pinned to 951b0fc683)
Solutions
- Recover from a newer checkpoint whose beginAddress >= device.StartSegment (check logger line 'Available segment range on device').
- Restore the full log directory (all segments, not just the checkpoint) from backup so StartSegment <= firstValidSegment.
- Delete the stale checkpoint and recover from a later one, or start fresh if the data is disposable.
- Ensure the log device path and the checkpoint directory always move together and are never partially pruned.
Example fix
// before: recover from an old checkpoint whose beginAddress predates surviving segments store.Recover(); // after: pick the latest compatible checkpoint, or restore missing segments // restore log dir from backup first, then store.Recover();
Defensive patterns
Strategy: validation
Validate before calling
// Before Recover: ensure the checkpoint's begin address is within surviving segments
var firstNeededSeg = (int)(recoveredCheckpoint.beginAddress >> logSettings.SegmentSizeBits);
if (firstNeededSeg < logDevice.StartSegment)
throw new InvalidOperationException("Checkpoint begin address predates surviving log segments; restore backup or use a later checkpoint"); Try / catch
try { store.Recover(); }
catch (TsavoriteException ex) when (ex.Message.Contains("first available segment on disk"))
{
// checkpoint/device mismatch: restore full log dir or pick a later checkpoint
logger.LogError(ex, "Recovery segment mismatch; checkpoint is older than surviving data");
throw;
} Prevention
- Never prune log segment files independent of checkpoints.
- Keep checkpoint metadata and log directory in lockstep when moving or backing up.
- Verify 'Available segment range on device' log line covers the checkpoint before recovering.
When it happens
Trigger: Recovering from a HybridLogCheckpoint whose info.beginAddress points below device.StartSegment. Happens when the log device was trimmed (TruncateUntilAddress / RemoveSegment) or a separate process deleted on-disk segments after the checkpoint was taken, or when checkpoint and device directories are out of sync.
Common situations: Recovery attempted against a partially deleted/truncated log directory; checkpoint file copied without its corresponding data segments; manual cleanup of segment files; a prior recovery or store open trimmed the head past this checkpoint's begin address; mismatched checkpoint/log paths after a directory move.
Related errors
- Unable to set last valid segment to {lastValidSegment}, last
- No snapshot object-log data available while copying objects
- Page read from storage failed, skipping page. Inner exceptio
- Option {fileType} not supported
- Checkpoint history unavailable, need full checkpoint for {en
AI-assisted analysis of microsoft/garnet@951b0fc683 (2026-08-13).
Data as JSON: /api/errors/b23b0cd021e2f9b9.
Report an issue: GitHub.