{"record":{"id":"dceaa73af0520e42","repo":"microsoft/garnet","slug":"page-read-from-storage-failed-skipping-page-inne","errorCode":null,"errorMessage":"Page read from storage failed, skipping page. Inner exception: ","messagePattern":"Page read from storage failed, skipping page\\. Inner exception: ","errorType":"exception","errorClass":"TsavoriteException","httpStatus":null,"severity":"error","filePath":"libs/storage/Tsavorite/cs/src/core/Allocator/ScanIteratorBase.cs","lineNumber":339,"sourceCode":"                epoch?.Suspend();\n                loadCompletionEvents[currentFrame].Wait(loadCTSs[currentFrame].Token); // Ensure we have completed ongoing load\n            }\n            catch (Exception e)\n            {\n                // Exception occurred so skip the page containing the currentAddress, and reinitialize the loaded page and cancellation token for the current frame.\n                // The exception may have been an OperationCanceledException.\n                loadedPages[currentFrame] = -1;\n                loadCTSs[currentFrame] = new CancellationTokenSource();\n                _ = Utility.MonotonicUpdate(ref nextAddress, GetLogicalAddressOfStartOfPage(1 + allocator.GetPageOfAddress(currentAddress, logPageSizeBits), logPageSizeBits), out _);\n\n                // Callers may be looking for an OCE so throw that if it's what we got.\n                if (e is OperationCanceledException)\n                {\n                    logger?.LogWarning(e, \"Wait for frame load was canceled, skipping page. CurrentAddress: {currentAddress}, currentFrame: {currentFrame}\", AddressString(currentAddress), currentFrame);\n                    throw;\n                }\n                else\n                    throw new TsavoriteException(\"Page read from storage failed, skipping page. Inner exception: \" + e.ToString());\n            }\n            finally\n            {\n                epoch?.Resume();\n            }\n            return true;\n        }\n\n        /// <summary>\n        /// Dispose iterator\n        /// </summary>\n        public virtual void Dispose()\n        {\n            // Wait for all deferred DoReadPage callbacks and their async I/O to complete before freeing\n            // resources. The counter is incremented before BumpCurrentEpoch registration and decremented\n            // in AsyncReadPageFromDeviceToFrameCallback when I/O completes, so reaching zero guarantees\n            // no outstanding access to our state. The deferred callbacks will be drained by other threads'\n            // epoch operations (Resume, Suspend, ProtectAndDrain).","sourceCodeStart":321,"sourceCodeEnd":357,"githubUrl":"https://github.com/microsoft/garnet/blob/951b0fc6838721f89d102c2bbe1b914e8d39d700/libs/storage/Tsavorite/cs/src/core/Allocator/ScanIteratorBase.cs#L321-L357","documentation":"ScanIteratorBase loads pages from memory/disk while iterating. If a page load throws and the exception is not OperationCanceledException, it is wrapped and rethrown as a TsavoriteException with the original exception's full ToString appended. This is the catch-all for I/O, deserialization, or device failures encountered while bringing a page into the scan frame.","triggerScenarios":"A disk/memory page read fails during a scan: device read error, missing or corrupt checkpoint page, closed/disposed device, permission denied on the storage path, hash/log page returning unexpected bytes, or storage disconnected mid-scan.","commonSituations":"Scanning a checkpoint that was deleted or moved while the scan ran; storage on a network mount that dropped; checkpoint format/version mismatch after an upgrade; disk full or hardware fault; scanning after the device was disposed.","solutions":["Inspect the inner exception text embedded in the message — it carries the real IOException/UnauthorizedAccessException/etc.","Verify the storage device/path still exists and is readable before scanning.","Reload from a known-good checkpoint and ensure it is not deleted during the scan.","For transient I/O (network mount hiccup), stabilize storage then restart the scan.","Check checkpoint version compatibility if this started after a Tsavorite upgrade."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Before scanning, confirm the device and checkpoint are present and readable\nif (!storageDevice.Exists || checkpoint is null)\n    throw new InvalidOperationException(\"storage/checkpoint unavailable for scan\");","typeGuard":null,"tryCatchPattern":"try { while (scanIterator.GetNext(...)) { /* ... */ } }\ncatch (TsavoriteException ex) when (ex.Message.StartsWith(\"Page read from storage failed\"))\n{\n    // ex.Message embeds the inner exception's ToString; parse/inspect it\n    logger.LogError(ex, \"scan aborted; inner: {Inner}\", ex.InnerException);\n    // decide: retry on transient I/O, or fail fast on corrupt checkpoint\n}","preventionTips":["Keep checkpoints alive for the duration of any scan that depends on them.","Validate device accessibility before starting a scan.","Re-test scans after Tsavorite upgrades for checkpoint-format compatibility.","Monitor disk health for the storage path."],"tags":["tsavorite","io","disk","checkpoint","scan","storage"],"backgroundTag":null,"analyzedSha":"951b0fc6838721f89d102c2bbe1b914e8d39d700","analyzedAt":"2026-08-13T19:01:32.939Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}