microsoft/garnet · error · GarnetException

MigrateSession Invalid TransferOption {transferOption}

Error message

MigrateSession Invalid TransferOption {transferOption}

What it means

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.

Source

Thrown at libs/cluster/Server/Migration/MigrateSessionKeyAccess.cs:24

using Garnet.common;
using Tsavorite.core;

namespace Garnet.cluster
{
    internal sealed unsafe partial class MigrateSession : IDisposable
    {
        /// <summary>
        /// Wait for config propagation based on the type of MigrateSession that is currently in progress
        /// </summary>
        /// <exception cref="GarnetException"></exception>
        private Task WaitForConfigPropagationAsync()
        {
            if (transferOption == TransferOption.KEYS)
                return clusterSession.UnsafeBumpAndWaitForEpochTransitionAsync();
            else if (transferOption == TransferOption.SLOTS)
                return clusterProvider.BumpAndWaitForEpochTransitionAsync();
            else
                throw new GarnetException($"MigrateSession Invalid TransferOption {transferOption}");
        }

        /// <summary>
        /// Check if it is safe to operate on the provided key when a slot state is set to MIGRATING
        /// </summary>
        /// <param name="key"></param>
        /// <param name="slot"></param>
        /// <param name="readOnly"></param>
        /// <returns></returns>
        /// <exception cref="GarnetException"></exception>
        public bool CanAccessKey(PinnedSpanByte key, int slot, bool readOnly)
        {
            // Skip operation check since this session is not responsible for migrating the associated slot
            if (!_sslots.Contains(slot))
                return true;

            var state = SketchStatus.INITIALIZING;
            foreach (var migrateTask in migrateOperation)

View on GitHub (pinned to 951b0fc683)

Solutions

  1. Confirm the MigrateSession is created with an explicit TransferOption.KEYS or TransferOption.SLOTS based on the MIGRATE variant issued.
  2. Add a constructor/property assertion that transferOption != NONE before the session can run.
  3. Guard the else branch to log transferOption so future regressions are diagnosible rather than opaque.

Example fix

// before
private Task WaitForConfigPropagationAsync()
{
    if (transferOption == TransferOption.KEYS) return ...;
    else if (transferOption == TransferOption.SLOTS) return ...;
    else throw new GarnetException($"MigrateSession Invalid TransferOption {transferOption}");
}
// after
private Task WaitForConfigPropagationAsync()
{
    Debug.Assert(transferOption is TransferOption.KEYS or TransferOption.SLOTS, $"unexpected {transferOption}");
    return transferOption == TransferOption.KEYS
        ? clusterSession.UnsafeBumpAndWaitForEpochTransitionAsync()
        : clusterProvider.BumpAndWaitForEpochTransitionAsync();
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate the session option before propagation waits
if (transferOption is not (TransferOption.KEYS or TransferOption.SLOTS))
    throw new InvalidOperationException($"MigrateSession requires KEYS or SLOTS, got {transferOption}");
await WaitForConfigPropagationAsync();

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of microsoft/garnet@951b0fc683 (2026-08-13). Data as JSON: /api/errors/b0f37f38949f70ea. Report an issue: GitHub.