microsoft/garnet · critical · RedisSerializationException

Specified transformer for RedisOptions property does not mat

Error message

Specified transformer for RedisOptions property does not match given types (Source: {typeof(TIn)}, Destination: {typeof(TOut)}).

What it means

Thrown indirectly via TryApplyTransform when a custom transformer type specified in RedisOptionAttribute.GarnetCustomTransformer does not implement IGarnetCustomTransformer<TIn, TOut> with the exact generic argument types matching the source and destination properties. This is a compile-time-to-runtime type contract violation in the framework's mapping layer.

Source

Thrown at libs/host/Configuration/Redis/RedisConfigSerializer.cs:223

                // Get destination property type
                var dstPropType = dstProp.PropertyType;

                // Try to convert source option to destination option
                object dstValue = null;

                // If custom transformer specified in RedisOptionAttribute, try to invoke transformer
                if (redisOptionAttr.GarnetCustomTransformer != null)
                {
                    var parameters = new[] { srcOptValue, null, null };
                    var result = (bool?)typeof(RedisConfigSerializer).GetMethod(nameof(TryApplyTransform), BindingFlags.NonPublic | BindingFlags.Static)
                        ?.MakeGenericMethod(srcOptValueType, dstPropType, redisOptionAttr.GarnetCustomTransformer)
                        .Invoke(null, parameters);
                    dstValue = parameters[1];

                    if (!result.HasValue || !result.Value)
                    {
                        throw new RedisSerializationException((string)parameters[2]);
                    }
                }
                // Try to convert to destination type
                else if (srcOptValueType != dstPropType)
                {
                    if (!TryChangeType(srcOptValue, srcOptValueType, dstPropType, out dstValue))
                    {
                        throw new RedisSerializationException(
                            $"Unable to convert property {prop.Name} in {typeof(RedisOptions)} to property {redisOptionAttr.GarnetOptionName} in {typeof(Options)}.");
                    }
                }
                // Source and destination types are the same with no transformer specified
                else
                {
                    dstValue = srcOptValue;
                }

                // Set the destination property with the converted value

View on GitHub (pinned to 951b0fc683)

Solutions

  1. Check the error message for the expected Source (TIn) and Destination (TOut) types.
  2. Update the custom transformer class to implement IGarnetCustomTransformer<TIn, TOut> with the correct types.
  3. If the property types changed, update both the transformer and the RedisOptionAttribute.

Example fix

// before: transformer implements wrong generic args
//   class MyTransformer : IGarnetCustomTransformer<int, string> { ... }
//   // but source is actually 'long'

// after:
//   class MyTransformer : IGarnetCustomTransformer<long, string> { ... }
Defensive patterns

Strategy: validation

Validate before calling

// Verify a transformer type matches the expected interface before assignment
var transformerType = typeof(MyTransformer);
var expectedInterface = typeof(IGarnetCustomTransformer<,>).MakeGenericType(srcType, dstType);
if (!expectedInterface.IsAssignableFrom(transformerType))
    throw new InvalidOperationException(
        $"Transformer {transformerType.Name} must implement {expectedInterface.Name}");

Type guard

static bool TransformerMatchesTypes(Type transformerType, Type srcType, Type dstType)
{
    var expectedInterface = typeof(IGarnetCustomTransformer<,>).MakeGenericType(srcType, dstType);
    return expectedInterface.IsAssignableFrom(transformerType);
}

Prevention

When it happens

Trigger: A RedisOptionAttribute has a GarnetCustomTransformer set to a type whose IGarnetCustomTransformer<TIn,TOut> generic arguments don't match the RedisOptions property type (TIn) or the Options property type (TOut). The check at RedisConfigSerializer.cs:264 uses IsAssignableFrom and fails.

Common situations: Changing a property type on either RedisOptions or Options without updating the transformer's generic arguments; using a transformer designed for a different property pair; framework development error.

Related errors


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