{"record":{"id":"958d609c53940ec3","repo":"Humanizr/Humanizer","slug":"unsupported-number-to-words-contract-member-kind","errorCode":null,"errorMessage":"Unsupported number-to-words contract member kind '{member.Kind}'.","messagePattern":"Unsupported number-to-words contract member kind '(.+?)'\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Humanizer.SourceGenerators/Generators/ProfileCatalogs/NumberToWordsEngineContractFactory.cs","lineNumber":423,"sourceCode":"                \"string-array\" => CreateStringArrayExpression(EngineContractUtilities.GetRequiredElement(root, member.SourcePath)),\n                \"optional-string-array\" => EngineContractUtilities.TryGetElement(root, member.SourcePath, out var optionalArray)\n                    ? CreateStringArrayExpression(optionalArray)\n                    : \"Array.Empty<string>()\",\n                \"int-string-dictionary\" => CreateStringIntFrozenDictionaryExpression(EngineContractUtilities.GetRequiredElement(root, member.SourcePath)),\n                \"nullable-int-string-dictionary\" => CreateNullableIntStringDictionaryValue(root, member),\n                \"string-string-dictionary\" => CreateStringStringFrozenDictionaryExpression(EngineContractUtilities.GetRequiredElement(root, member.SourcePath)),\n                \"nullable-string-string-dictionary\" => EngineContractUtilities.TryGetElement(root, member.SourcePath, out var optionalStringDictionary)\n                    ? CreateOptionalStringStringFrozenDictionaryExpression(root, EngineContractUtilities.GetLeafPropertyName(member.SourcePath))\n                    : member.MissingValue == \"empty\"\n                        ? \"FrozenDictionary<string, string>.Empty\"\n                        : \"null\",\n                \"char-string-dictionary\" => CreateCharStringFrozenDictionaryExpression(EngineContractUtilities.GetRequiredElement(root, member.SourcePath)),\n                \"nullable-char-string-dictionary\" => EngineContractUtilities.TryGetElement(root, member.SourcePath, out var optionalCharDictionary)\n                    ? CreateCharStringFrozenDictionaryExpression(optionalCharDictionary)\n                    : \"null\",\n                \"nullable-int-set\" => CreateNullableIntSetValue(root, member),\n                \"builder\" => CreateBuilderValue(root, member),\n                _ => throw new InvalidOperationException($\"Unsupported number-to-words contract member kind '{member.Kind}'.\")\n            };\n\n        static string CreateObjectValue(JsonElement root, EngineContractMember member, bool useCultureParameter)\n        {\n            var objectRoot = string.IsNullOrWhiteSpace(member.SourcePath)\n                ? root\n                : EngineContractUtilities.GetRequiredElement(root, member.SourcePath);\n\n            // Nested profile objects let the YAML stay grouped by meaning while the generated code\n            // still calls an explicit runtime constructor shape. This keeps the authoring surface\n            // readable without paying any runtime mapping cost.\n            return member.TypeName is null\n                ? \"new(\" + CreateConstructorValues(objectRoot, member.Members, useCultureParameter) + \")\"\n                : \"new \" + member.TypeName + \"(\" + CreateConstructorValues(objectRoot, member.Members, useCultureParameter) + \")\";\n        }\n\n        static string CreateEnumValue(JsonElement root, EngineContractMember member)\n        {","sourceCodeStart":405,"sourceCodeEnd":441,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer.SourceGenerators/Generators/ProfileCatalogs/NumberToWordsEngineContractFactory.cs#L405-L441","documentation":"The number-to-words contract factory maps each contract member 'kind' to a C# expression generator via a switch expression. If a member's kind is not one of the ~20 supported kinds (string, int64, enum, builder, profile-object, etc.), the default arm throws. This is a generator-level configuration error, not a locale YAML issue.","triggerScenarios":"An EngineContractMember is defined with a Kind value not handled by the switch in CreateMemberValue. For example, a new kind 'decimal' was added to a contract definition but no corresponding case exists in the factory. Typically introduced by editing EngineContractCatalog.","commonSituations":"Adding a new member kind to a contract definition without adding a factory case. Renaming a kind in one place but not the other. Version mismatch between contract definitions and the factory after a partial merge.","solutions":["Add a matching case to the CreateMemberValue switch expression in NumberToWordsEngineContractFactory.cs for the new kind.","If the kind was mistyped, correct the Kind value in the EngineContractMember definition to match a supported kind.","Review the EngineContractCatalog definitions for the affected engine and verify every member kind has a factory case."],"exampleFix":"// before (contract member with unsupported kind)\nnew EngineContractMember(\n    kind: \"decimal\",\n    sourcePath: \"factor\",\n    ...)\n// after — use a supported kind or add a factory case\nnew EngineContractMember(\n    kind: \"int64\",\n    sourcePath: \"factor\",\n    ...)","handlingStrategy":"validation","validationCode":"// Validate all contract member kinds are supported before generation:\nstatic readonly HashSet<string> SupportedKinds = new()\n{\n    \"profile-object\",\"optional-profile-object\",\"culture\",\"string\",\"nullable-string\",\n    \"bool\",\"presence-bool\",\"int64\",\"nullable-int64\",\"int32\",\"enum\",\n    \"string-array\",\"optional-string-array\",\"int-string-dictionary\",\n    \"nullable-int-string-dictionary\",\"string-string-dictionary\",\n    \"nullable-string-string-dictionary\",\"char-string-dictionary\",\n    \"nullable-char-string-dictionary\",\"nullable-int-set\",\"builder\"\n};\nforeach (var m in contract.Members)\n    if (!SupportedKinds.Contains(m.Kind))\n        throw new ArgumentException($\"Unsupported kind '{m.Kind}' in contract.\");","typeGuard":"static bool IsSupportedMemberKind(string kind) =>\n    SupportedKinds.Contains(kind);","tryCatchPattern":null,"preventionTips":["When adding a new member kind to EngineContractMember, immediately add the corresponding factory case.","Write a test that enumerates all contracts and asserts every member kind has a factory case.","Use constants or an enum for kind values to prevent typos."],"tags":["source-generator","number-to-words","contract","engine-contract","build-time"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}