{"record":{"id":"89aca008137b6a3a","repo":"microsoft/garnet","slug":"unable-to-find-property-in-typeof-options-named","errorCode":null,"errorMessage":"Unable to find property in {typeof(Options)} named {redisOptionAttr.GarnetOptionName} that matches {typeof(Options)} property {prop.Name}","messagePattern":"Unable to find property in (.+?) named (.+?) that matches (.+?) property (.+?)","errorType":"exception","errorClass":"RedisSerializationException","httpStatus":null,"severity":"critical","filePath":"libs/host/Configuration/Redis/RedisConfigSerializer.cs","lineNumber":198,"sourceCode":"        /// <param name=\"options\">The Options object to populate</param>\n        /// <returns>True if succeeded</returns>\n        public static bool TryPopulateOptions(RedisOptions redisOptions, Options options)\n        {\n            foreach (var prop in GetProperties())\n            {\n                // Get source option value\n                var srcOpt = prop.GetValue(redisOptions);\n\n                // Ignore if source option is not set\n                if (srcOpt == null) continue;\n\n                // Get matching Options property defined by RedisOptionAttribute decorating RedisOption property\n                var redisOptionAttr = (RedisOptionAttribute)prop.GetCustomAttributes(typeof(RedisOptionAttribute), false).First();\n                var dstProp = typeof(Options).GetProperty(redisOptionAttr.GarnetOptionName);\n\n                // Check if destination property exists\n                if (dstProp == null)\n                    throw new RedisSerializationException(\n                        $\"Unable to find property in {typeof(Options)} named {redisOptionAttr.GarnetOptionName} that matches {typeof(Options)} property {prop.Name}\");\n\n                // Get source option underlying value & type\n                var srcOptValueProp = prop.PropertyType.GetProperty(nameof(Option<object>.Value));\n                var srcOptValueType = prop.PropertyType.GenericTypeArguments.First();\n                var srcOptValue = srcOptValueProp.GetValue(srcOpt);\n\n                // Get destination property type\n                var dstPropType = dstProp.PropertyType;\n\n                // Try to convert source option to destination option\n                object dstValue = null;\n\n                // If custom transformer specified in RedisOptionAttribute, try to invoke transformer\n                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)","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/microsoft/garnet/blob/951b0fc6838721f89d102c2bbe1b914e8d39d700/libs/host/Configuration/Redis/RedisConfigSerializer.cs#L180-L216","documentation":"Thrown by RedisConfigSerializer.TryPopulateOptions when a RedisOptions property's RedisOptionAttribute specifies a GarnetOptionName that does not exist as a property on the Options class. This is a framework-level mapping inconsistency — the attribute references a destination property that was renamed, removed, or misspelled. End users should not normally hit this unless running mismatched library versions.","triggerScenarios":"Calling TryPopulateOptions with a set of RedisOptions whose attributes reference Options property names that no longer exist (e.g., after a refactor that renamed an Options property without updating the corresponding RedisOptionAttribute.GarnetOptionName).","commonSituations":"Running a Garnet build where libs/host Configuration/Options.cs was modified (property renamed/removed) but RedisOptions attributes were not updated; using a custom build with incomplete patches; version mismatch between assemblies.","solutions":["Ensure all assemblies (libs/host, libs/server) are from the same Garnet build/version.","If you modified Options.cs property names, update every RedisOptionAttribute.GarnetOptionName that references the old name.","Search the codebase for the GarnetOptionName value in the error to find the stale attribute."],"exampleFix":"// before: Options.cs renamed 'Port' to 'ListenerPort'\n//   but RedisOptions still has:\n//   [RedisOption(Key = \"port\", GarnetOptionName = \"Port\")]\n\n// after: update the attribute\n//   [RedisOption(Key = \"port\", GarnetOptionName = \"ListenerPort\")]","handlingStrategy":"validation","validationCode":"// Framework-level check: verify all RedisOptionAttribute.GarnetOptionName values exist on Options\nforeach (var prop in typeof(RedisOptions).GetProperties()\n    .Where(p => Attribute.IsDefined(p, typeof(RedisOptionAttribute))))\n{\n    var attr = (RedisOptionAttribute)prop.GetCustomAttributes(typeof(RedisOptionAttribute), false).First();\n    if (typeof(Options).GetProperty(attr.GarnetOptionName) == null)\n        throw new InvalidOperationException(\n            $\"RedisOptionAttribute on {prop.Name} references non-existent Options property '{attr.GarnetOptionName}'\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When renaming or removing Options properties, update all RedisOptionAttribute.GarnetOptionName references.","Add a unit test that validates every RedisOptionAttribute.GarnetOptionName resolves to a real Options property.","Keep all Garnet assemblies version-aligned in deployments."],"tags":["redis-config","reflection","framework-bug","configuration"],"backgroundTag":null,"analyzedSha":"951b0fc6838721f89d102c2bbe1b914e8d39d700","analyzedAt":"2026-08-13T19:01:32.939Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}