microsoft/garnet · critical · TsavoriteException
Unable to set last valid segment to {lastValidSegment}, last
Error message
Unable to set last valid segment to {lastValidSegment}, last available segment on disk is {lastAvailSegment} What it means
Thrown by VerifyRecoveryInfo during recovery when the checkpoint's flushed address maps to a segment (lastValidSegment) that is beyond the last segment present on the log device (lastAvailSegment). Recovery needs the tail segment of the log to reach the checkpoint's flushed/commit point, but that segment is missing on disk.
Source
Thrown at libs/storage/Tsavorite/cs/src/core/Allocator/AllocatorBase.cs:732
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);
}
}
}
/// <summary>Allocate a pinned byte[] for the page at <paramref name="index"/></summary>View on GitHub (pinned to 951b0fc683)
Solutions
- Restore the missing tail segments from backup so lastAvailSegment >= lastValidSegment.
- Recover from an earlier checkpoint whose flushed address falls within the surviving segment range.
- Verify the log directory is complete (no missing segment files numbered <= lastValidSegment) before calling Recover.
- If segments are genuinely lost and no earlier checkpoint is available, start the store fresh and accept data loss.
Example fix
// before store.Recover(); // lastValidSegment > lastAvailSegment // after: recover from an earlier checkpoint within the available segment range checkpointManager.SetRecoveredHLCInfo(earlierCheckpoint); store.Recover();
Defensive patterns
Strategy: validation
Validate before calling
var lastNeededSeg = (int)(recoveredCheckpoint.flushedLogicalAddress >> logSettings.SegmentSizeBits);
if (lastNeededSeg > logDevice.EndSegment)
throw new InvalidOperationException("Checkpoint needs tail segments missing from the log device"); Try / catch
try { store.Recover(); }
catch (TsavoriteException ex) when (ex.Message.Contains("last available segment on disk"))
{
logger.LogError(ex, "Recovery needs tail segments not present; restore backup or use earlier checkpoint");
throw;
} Prevention
- Always back up the entire log directory, including the newest segment files.
- Confirm no segment files numbered between StartSegment and the checkpoint tail are missing.
- Recover from the most recent checkpoint that fits within the available segment range.
When it happens
Trigger: Recovering from a checkpoint whose finalLogicalAddress / flushedLogicalAddress falls in a segment greater than device.EndSegment (and the in-memory FlushedUntilAddress doesn't extend it). Occurs when tail segments were lost, the log directory is incomplete, or checkpoint metadata points further than the data present.
Common situations: Incomplete copy of the log directory (missing the newest segment files); checkpoint taken then tail segments deleted; disk corruption/loss of the most recent segments; a checkpoint that is ahead of the actually-flushed data (crash between checkpoint commit and segment flush).
Related errors
- Unable to set first valid segment to {firstValidSegment}, fi
- 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/f351714e6f4c7408.
Report an issue: GitHub.