{"record":{"id":"f4241b5b90cb0641","repo":"microsoft/garnet","slug":"unable-to-convert-property-prop-name-in-typeof","errorCode":null,"errorMessage":"Unable to convert property {prop.Name} in {typeof(RedisOptions)} to property {redisOptionAttr.GarnetOptionName} in {typeof(Options)}.","messagePattern":"Unable to convert property (.+?) in (.+?) to property (.+?) in (.+?)\\.","errorType":"exception","errorClass":"RedisSerializationException","httpStatus":null,"severity":"critical","filePath":"libs/host/Configuration/Redis/RedisConfigSerializer.cs","lineNumber":231,"sourceCode":"                if (redisOptionAttr.GarnetCustomTransformer != null)\n                {\n                    var parameters = new[] { srcOptValue, null, null };\n                    var result = (bool?)typeof(RedisConfigSerializer).GetMethod(nameof(TryApplyTransform), BindingFlags.NonPublic | BindingFlags.Static)\n                        ?.MakeGenericMethod(srcOptValueType, dstPropType, redisOptionAttr.GarnetCustomTransformer)\n                        .Invoke(null, parameters);\n                    dstValue = parameters[1];\n\n                    if (!result.HasValue || !result.Value)\n                    {\n                        throw new RedisSerializationException((string)parameters[2]);\n                    }\n                }\n                // Try to convert to destination type\n                else if (srcOptValueType != dstPropType)\n                {\n                    if (!TryChangeType(srcOptValue, srcOptValueType, dstPropType, out dstValue))\n                    {\n                        throw new RedisSerializationException(\n                            $\"Unable to convert property {prop.Name} in {typeof(RedisOptions)} to property {redisOptionAttr.GarnetOptionName} in {typeof(Options)}.\");\n                    }\n                }\n                // Source and destination types are the same with no transformer specified\n                else\n                {\n                    dstValue = srcOptValue;\n                }\n\n                // Set the destination property with the converted value\n                dstProp.SetValue(options, dstValue);\n            }\n\n            return true;\n        }\n\n        /// <summary>\n        /// Tries to apply a custom IGarnetCustomTransformer to transform a RedisOptions property to an Options property","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/microsoft/garnet/blob/951b0fc6838721f89d102c2bbe1b914e8d39d700/libs/host/Configuration/Redis/RedisConfigSerializer.cs#L213-L249","documentation":"Thrown by RedisConfigSerializer.TryPopulateOptions when a RedisOptions property and its corresponding Options property have different types, no custom transformer is specified, and TryChangeType fails to convert between them. This indicates a type mapping gap in the framework's option-population logic.","triggerScenarios":"During TryPopulateOptions, the source property type (from RedisOptions) and destination property type (from Options) differ, no GarnetCustomTransformer is set on the attribute, and the value cannot be converted via TypeDescriptor or Convert.ChangeType.","commonSituations":"Modifying a RedisOptions or Options property type without adding a custom transformer; framework version mismatch where a property type was changed in one assembly but not the other.","solutions":["Add a GarnetCustomTransformer to the RedisOptionAttribute that handles the type conversion.","Align the types of the RedisOptions property and Options property.","Ensure all assemblies are from the same build to avoid type drift."],"exampleFix":"// before: RedisOptions.Timeout is string, Options.Timeout is TimeSpan, no transformer\n\n// after: add a transformer\n//   [RedisOption(Key = \"timeout\", GarnetOptionName = \"Timeout\",\n//       GarnetCustomTransformer = typeof(StringToTimeSpanTransformer))]\n//   public Option<string> Timeout { get; set; }","handlingStrategy":"validation","validationCode":"// Check type convertibility between RedisOptions and Options property types\nvar srcType = typeof(RedisOptions).GetProperty(propName).PropertyType.GenericTypeArguments.First();\nvar dstType = typeof(Options).GetProperty(dstPropName).PropertyType;\nif (srcType != dstType)\n{\n    var converter = TypeDescriptor.GetConverter(srcType);\n    if (!converter.CanConvertTo(dstType) && !TypeDescriptor.GetConverter(dstType).CanConvertFrom(srcType))\n        throw new InvalidOperationException($\"No conversion path from {srcType.Name} to {dstType.Name} for {propName}\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When property types differ between RedisOptions and Options, always provide a GarnetCustomTransformer.","Add build-time tests that verify TryPopulateOptions succeeds for all mapped properties.","Keep assembly versions aligned to avoid type drift."],"tags":["redis-config","type-conversion","framework-bug","configuration"],"backgroundTag":null,"analyzedSha":"951b0fc6838721f89d102c2bbe1b914e8d39d700","analyzedAt":"2026-08-13T19:01:32.939Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}