{"record":{"id":"e95f879d41529b57","repo":"microsoft/garnet","slug":"recoverypath-is-required","errorCode":null,"errorMessage":"recoveryPath is required.","messagePattern":"recoveryPath is required\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"libs/native/bftree-garnet/BfTreeService.cs","lineNumber":557,"sourceCode":"                throw new InvalidOperationException(\"Failed to take CPR snapshot of BfTree.\");\n        }\n\n        /// <summary>\n        /// Recover a BfTree from a CPR snapshot file. Unified API for disk-backed and\n        /// memory-backed (cache_only) trees — the storage backend is recorded in the\n        /// snapshot and inferred by the native library.\n        /// </summary>\n        /// <param name=\"recoveryPath\">Source CPR snapshot file path.</param>\n        /// <param name=\"enableSnapshots\">Enable CPR snapshot support on the recovered tree.\n        /// Required if the recovered tree will be snapshotted later (flush/checkpoint/migration).</param>\n        /// <param name=\"storageBackend\">Storage backend of the recovered tree (for managed tracking).</param>\n        public static BfTreeService RecoverFromCprSnapshot(\n            string recoveryPath,\n            bool enableSnapshots,\n            StorageBackendType storageBackend)\n        {\n            if (string.IsNullOrEmpty(recoveryPath))\n                throw new ArgumentException(\"recoveryPath is required.\", nameof(recoveryPath));\n\n            var recoveryBytes = Encoding.UTF8.GetBytes(recoveryPath);\n            byte useSnapshot = (byte)(enableSnapshots ? 1 : 0);\n            nint treePtr;\n            fixed (byte* rp = recoveryBytes)\n            {\n                treePtr = NativeBfTreeMethods.bftree_new_from_cpr_snapshot(\n                    rp, recoveryBytes.Length,\n                    useSnapshot,\n                    null, 0);\n            }\n            if (treePtr == 0)\n                throw new InvalidOperationException($\"Failed to recover BfTree from CPR snapshot '{recoveryPath}'.\");\n            return new BfTreeService(treePtr, storageBackend, filePath: null);\n        }\n\n        /// <summary>\n        /// Drains scan iterator via callback — zero per-record allocation.","sourceCodeStart":539,"sourceCodeEnd":575,"githubUrl":"https://github.com/microsoft/garnet/blob/951b0fc6838721f89d102c2bbe1b914e8d39d700/libs/native/bftree-garnet/BfTreeService.cs#L539-L575","documentation":"Thrown by the static RecoverFromCprSnapshot when recoveryPath is null or empty. The native bftree_new_from_cpr_snapshot needs a source file path; an empty one is rejected early by the managed wrapper with an ArgumentException before any native call.","triggerScenarios":"Calling RecoverFromCprSnapshot(null, ...) or RecoverFromCprSnapshot(\"\", ...) — typically when the recovery source path was not supplied (e.g. a restart where the last snapshot path was not persisted, or a migration step that omitted the source).","commonSituations":"Startup recovery where the snapshot path is read from an unset environment variable or config key; a test that forgets to pass the snapshot path; a failover routine that has no recorded snapshot location.","solutions":["Persist the snapshot path durably so recovery can find it after restart.","Validate !string.IsNullOrWhiteSpace(recoveryPath) before calling.","If no snapshot exists, fall back to creating a fresh tree instead of recovering.","Fail fast at startup with a clear config error if recovery is required but the path is unset."],"exampleFix":"// before\nvar tree = BfTreeService.RecoverFromCprSnapshot(recoveryPath, enableSnapshots: true, backend);\n\n// after\nif (string.IsNullOrWhiteSpace(recoveryPath))\n    throw new InvalidOperationException(\"No CPR snapshot path configured for recovery.\");\nvar tree = BfTreeService.RecoverFromCprSnapshot(recoveryPath, enableSnapshots: true, backend);","handlingStrategy":"validation","validationCode":"if (string.IsNullOrWhiteSpace(recoveryPath))\n    throw new ArgumentException(\"recoveryPath is required.\", nameof(recoveryPath));","typeGuard":"static bool HasRecoveryPath(string path) => !string.IsNullOrWhiteSpace(path);","tryCatchPattern":"try { tree = BfTreeService.RecoverFromCprSnapshot(recoveryPath, true, backend); }\ncatch (ArgumentException ex) when (ex.ParamName == nameof(recoveryPath)) { tree = CreateFreshTree(); }","preventionTips":["Persist the snapshot path durably for restart recovery.","Fail fast at startup if recovery is mandatory but the path is unset.","Fall back to a fresh tree when no snapshot path exists."],"tags":["bftree","native-interop","recovery","invalid-argument","configuration"],"backgroundTag":null,"analyzedSha":"951b0fc6838721f89d102c2bbe1b914e8d39d700","analyzedAt":"2026-08-13T19:01:32.939Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}