{"record":{"id":"c66d98dad301d271","repo":"microsoft/FASTER","slug":"unable-to-set-last-valid-segment-to-lastvalidsegment-last","errorCode":null,"errorMessage":"Unable to set last valid segment to {lastValidSegment}, last available segment on disk is {lastAvailSegment}","messagePattern":"Unable to set last valid segment to (.+?), last available segment on disk is (.+?)","errorType":"exception","errorClass":"FasterException","httpStatus":null,"severity":"error","filePath":"cs/src/core/Allocator/AllocatorBase.cs","lineNumber":1120,"sourceCode":"            var lastAvailSegment = device.EndSegment;\n\n            if (FlushedUntilAddress > GetFirstValidLogicalAddress(0))\n            {\n                int currTailSegment = (int)(FlushedUntilAddress >> LogSegmentSizeBits);\n                if ((FlushedUntilAddress & ((1L << LogSegmentSizeBits) - 1)) == 0)\n                    currTailSegment--;\n\n                if (currTailSegment > lastAvailSegment)\n                    lastAvailSegment = currTailSegment;\n            }\n\n            logger?.LogInformation(\"Available segment range on device: [{firstAvailSegment}--{lastAvailSegment}]\", firstAvailSegment, lastAvailSegment);\n\n            if (firstValidSegment < firstAvailSegment)\n                throw new FasterException($\"Unable to set first valid segment to {firstValidSegment}, first available segment on disk is {firstAvailSegment}\");\n\n            if (lastAvailSegment >= 0 && lastValidSegment > lastAvailSegment)\n                throw new FasterException($\"Unable to set last valid segment to {lastValidSegment}, last available segment on disk is {lastAvailSegment}\");\n\n            if (trimLog)\n            {\n                logger?.LogInformation(\"Trimming disk segments until (not including) {firstSegment}\", firstValidSegment);\n                TruncateUntilAddressBlocking(firstValidSegment << LogSegmentSizeBits);\n\n                for (int s = lastValidSegment + 1; s <= lastAvailSegment; s++)\n                {\n                    logger?.LogInformation(\"Trimming tail segment {s} on disk\", s);\n                    RemoveSegment(s);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Initialize allocator\n        /// </summary>\n        /// <param name=\"firstValidAddress\"></param>","sourceCodeStart":1102,"sourceCodeEnd":1138,"githubUrl":"https://github.com/microsoft/FASTER/blob/321d872eabda6a0345c8bd76419f89723ed864ae/cs/src/core/Allocator/AllocatorBase.cs#L1102-L1138","documentation":"The mirror of the first-valid-segment check: after recovery scan, the checkpoint's last valid segment must not exceed the newest segment physically on disk. If the checkpoint claims a lastValidSegment beyond what the device holds, the tail of the log is missing and recovery would produce an incomplete/corrupt state, so it throws. Guarding against truncated or partially deleted log tails.","triggerScenarios":"Recovering a checkpoint whose lastValidSegment is greater than the last segment found on the attached LogDevice - e.g. tail log files deleted, disk full during writes lost data, or a partial checkpoint copy.","commonSituations":"Incomplete backup/restore of the log directory; a device that failed mid-write losing tail segments; copying only part of the checkpoint/log files to another machine.","solutions":["Restore the complete log files (all segments up to lastValidSegment) from backup before recovering.","Recover from an older checkpoint whose lastValidSegment exists on the device.","Attach the original device containing the full segment range instead of a partial copy."],"exampleFix":"// before\n// log dir contains only segments 0-3, checkpoint expects segments 0-7\nstore.Recover(checkpointSettings); // throws\n\n// after\n// restore segments 4-7 from backup, or recover from an older checkpoint:\nvar target = latestCheckpointWhoseLastSegmentExistsOnDisk();\nstore.Recover(target);","handlingStrategy":"try-catch","validationCode":"// confirm all segments up to the checkpoint tail exist on the device before recovery","typeGuard":null,"tryCatchPattern":"try { store.Recover(checkpointSettings); }\ncatch (FasterException ex) when (ex.Message.Contains(\"last valid segment\")) {\n    // restore missing tail segments from backup or pick an older checkpoint\n}","preventionTips":["Back up/restore the complete log directory atomically with checkpoints.","Verify file counts/sizes after copying log files between machines.","Monitor disk-full conditions that could truncate tail writes."],"tags":["csharp","recovery","faster","checkpoint"],"backgroundTag":"resource-not-found","analyzedSha":"321d872eabda6a0345c8bd76419f89723ed864ae","analyzedAt":"2026-09-15T22:18:00.693Z","contentChangedAt":"2026-09-15T22:18:00.693Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}