{"record":{"id":"b0f37f38949f70ea","repo":"microsoft/garnet","slug":"migratesession-invalid-transferoption-transferopt","errorCode":null,"errorMessage":"MigrateSession Invalid TransferOption {transferOption}","messagePattern":"MigrateSession Invalid TransferOption (.+?)","errorType":"exception","errorClass":"GarnetException","httpStatus":null,"severity":"error","filePath":"libs/cluster/Server/Migration/MigrateSessionKeyAccess.cs","lineNumber":24,"sourceCode":"using Garnet.common;\nusing Tsavorite.core;\n\nnamespace Garnet.cluster\n{\n    internal sealed unsafe partial class MigrateSession : IDisposable\n    {\n        /// <summary>\n        /// Wait for config propagation based on the type of MigrateSession that is currently in progress\n        /// </summary>\n        /// <exception cref=\"GarnetException\"></exception>\n        private Task WaitForConfigPropagationAsync()\n        {\n            if (transferOption == TransferOption.KEYS)\n                return clusterSession.UnsafeBumpAndWaitForEpochTransitionAsync();\n            else if (transferOption == TransferOption.SLOTS)\n                return clusterProvider.BumpAndWaitForEpochTransitionAsync();\n            else\n                throw new GarnetException($\"MigrateSession Invalid TransferOption {transferOption}\");\n        }\n\n        /// <summary>\n        /// Check if it is safe to operate on the provided key when a slot state is set to MIGRATING\n        /// </summary>\n        /// <param name=\"key\"></param>\n        /// <param name=\"slot\"></param>\n        /// <param name=\"readOnly\"></param>\n        /// <returns></returns>\n        /// <exception cref=\"GarnetException\"></exception>\n        public bool CanAccessKey(PinnedSpanByte key, int slot, bool readOnly)\n        {\n            // Skip operation check since this session is not responsible for migrating the associated slot\n            if (!_sslots.Contains(slot))\n                return true;\n\n            var state = SketchStatus.INITIALIZING;\n            foreach (var migrateTask in migrateOperation)","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/microsoft/garnet/blob/951b0fc6838721f89d102c2bbe1b914e8d39d700/libs/cluster/Server/Migration/MigrateSessionKeyAccess.cs#L6-L42","documentation":"Thrown by MigrateSession.WaitForConfigPropagationAsync when transferOption is neither KEYS nor SLOTS. TransferOption.NONE (the default, value 0) and any invalid cast fall through to the else branch. The method dispatches epoch-transition waits differently for key-scoped vs slot-scoped migrate sessions, so an unset option is a programming error.","triggerScenarios":"A MigrateSession constructed/used before its transferOption was set away from NONE, or a code path that creates a session with an out-of-range TransferOption value.","commonSituations":"A new migrate code path that forgets to choose KEYS vs SLOTS; a deserialized/reconstructed session object whose option defaulted to NONE; refactoring that changes the migrate constructor without setting the option.","solutions":["Confirm the MigrateSession is created with an explicit TransferOption.KEYS or TransferOption.SLOTS based on the MIGRATE variant issued.","Add a constructor/property assertion that transferOption != NONE before the session can run.","Guard the else branch to log transferOption so future regressions are diagnosible rather than opaque."],"exampleFix":"// before\nprivate Task WaitForConfigPropagationAsync()\n{\n    if (transferOption == TransferOption.KEYS) return ...;\n    else if (transferOption == TransferOption.SLOTS) return ...;\n    else throw new GarnetException($\"MigrateSession Invalid TransferOption {transferOption}\");\n}\n// after\nprivate Task WaitForConfigPropagationAsync()\n{\n    Debug.Assert(transferOption is TransferOption.KEYS or TransferOption.SLOTS, $\"unexpected {transferOption}\");\n    return transferOption == TransferOption.KEYS\n        ? clusterSession.UnsafeBumpAndWaitForEpochTransitionAsync()\n        : clusterProvider.BumpAndWaitForEpochTransitionAsync();\n}","handlingStrategy":"validation","validationCode":"// Validate the session option before propagation waits\nif (transferOption is not (TransferOption.KEYS or TransferOption.SLOTS))\n    throw new InvalidOperationException($\"MigrateSession requires KEYS or SLOTS, got {transferOption}\");\nawait WaitForConfigPropagationAsync();","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set transferOption in the MigrateSession constructor and assert it is never NONE.","Keep KEYS vs SLOTS selection driven by the MIGRATE command variant in one place.","Log the offending transferOption value in the exception for faster diagnosis."],"tags":["cluster","migration","enum-switch","garnet"],"backgroundTag":null,"analyzedSha":"951b0fc6838721f89d102c2bbe1b914e8d39d700","analyzedAt":"2026-08-13T19:01:32.939Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}