microsoft/garnet · error · RedisSerializationException

Unable to deserialize RedisOptions object. Unable to…

Error message

Unable to deserialize RedisOptions object. Unable to convert object of type {typeof(string)} to object of type {optType}. (Line: {lineCount}; Key: {key}; Property: {prop.Name}).

What it means

Thrown by RedisConfigSerializer.Deserialize when a non-array option value cannot be converted from string to the option's underlying type. This is the fallback after TryChangeType fails for scalar options — e.g., providing 'abc' for an integer property. The parser tried TypeDescriptor converters and Convert.ChangeType, all of which failed.

Solutions

  1. Check the property name and key in the error message to identify the directive.
  2. Provide a value that matches the expected type (e.g., integer for Port, valid boolean or numeric for timeout).
  3. Refer to the GarnetServerOptions property type for the correct value format.

Example fix

// before:
//   port abc

// after:
//   port 6379
Defensive patterns

Strategy: validation

Validate before calling

var propType = typeof(RedisOptions).GetProperty(key)?.PropertyType;
if (propType != null)
{
    var optType = propType.GenericTypeArguments.First();
    var converter = TypeDescriptor.GetConverter(optType);
    if (!converter.IsValid(value))
        throw new FormatException($"Value '{value}' is not valid for type {optType.Name} (key: {key})");
}

Type guard

static bool CanConvertScalar(string value, Type targetType)
{
    var converter = TypeDescriptor.GetConverter(targetType);
    return converter.IsValid(value);
}

Try / catch

try
{
    var redisOpts = RedisConfigSerializer.Deserialize(reader, logger);
}
catch (RedisSerializationException ex) when (ex.Message.Contains("Unable to convert object of type"))
{
    logger.LogError("Redis config value type mismatch: {msg}", ex.Message);
    throw;
}

Prevention

When it happens

Trigger: A config directive whose value is a single scalar that doesn't match the property type. For example, 'port abc' where Port expects an int, or 'timeout true' where the property expects a numeric value.

Common situations: Typographical errors in config files; unit mismatches (e.g., providing '10ms' where a raw integer is expected); locale-related number format issues; using a Redis directive name that maps to a different type than expected.

Related errors


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

Appendix: source

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

                        // Instantiate a new array
                        var elemType = optType.GetElementType();
                        newVal = Array.CreateInstance(elemType, values.Length);

                        // Try deserializing and setting array elements
                        for (var i = 0; i < values.Length; i++)
                        {
                            if (!TryChangeType(values[i], typeof(string), elemType, out var elem))
                                throw new RedisSerializationException(
                                    $"Unable to deserialize {nameof(RedisOptions)} object. Unable to convert object of type {typeof(string)} to object of type {elemType}. (Line: {lineCount}; Key: {key}; Property: {prop.Name}).");


                            ((Array)newVal).SetValue(elem, i);
                        }
                    }
                    else
                    {
                        throw new RedisSerializationException(
                            $"Unable to deserialize {nameof(RedisOptions)} object. Unable to convert object of type {typeof(string)} to object of type {optType}. (Line: {lineCount}; Key: {key}; Property: {prop.Name}).");
                    }
                }

                // Create a new Option<T> object
                var newOpt = Activator.CreateInstance(prop.PropertyType);

                // Set the underlying option value
                var valueProp = prop.PropertyType.GetProperty(nameof(Option<object>.Value));
                valueProp.SetValue(newOpt, newVal);

                // Set the options property to the new option object
                prop.SetValue(options, newOpt);

                // Append usage warning, if defined
                var redisOptionAttr = (RedisOptionAttribute)prop.GetCustomAttributes(typeof(RedisOptionAttribute), false).First();
                if (!string.IsNullOrEmpty(redisOptionAttr.UsageWarning))
                {

View on GitHub (pinned to 951b0fc683)