{"record":{"id":"63a8a3dd605e41fe","repo":"Humanizr/Humanizer","slug":"builder-members-require-a-builder-name","errorCode":null,"errorMessage":"Builder members require a builder name.","messagePattern":"Builder members require a builder name\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Humanizer.SourceGenerators/Generators/ProfileCatalogs/NumberToWordsEngineContractFactory.cs","lineNumber":482,"sourceCode":"        static string CreateNullableIntSetValue(JsonElement root, EngineContractMember member)\n        {\n            if (EngineContractUtilities.TryGetElement(root, member.SourcePath, out _))\n            {\n                return CreateNullableIntFrozenSetExpression(root, EngineContractUtilities.GetLeafPropertyName(member.SourcePath));\n            }\n\n            return member.MissingValue switch\n            {\n                \"empty\" => \"FrozenSet<int>.Empty\",\n                _ => \"null\"\n            };\n        }\n\n        static string CreateBuilderValue(JsonElement root, EngineContractMember member)\n        {\n            if (member.Builder is null)\n            {\n                throw new InvalidOperationException(\"Builder members require a builder name.\");\n            }\n\n            if (member.Builder == \"billion-strategy-cardinal-scale-array\" &&\n                !EngineContractUtilities.TryGetElement(root, member.SourcePath, out _))\n            {\n                return CreateLegacyBillionStrategyCardinalScaleArrayExpression(root);\n            }\n\n            var builderRoot = string.IsNullOrWhiteSpace(member.SourcePath)\n                ? root\n                : EngineContractUtilities.GetRequiredElement(root, member.SourcePath);\n\n            // Builders exist for repeated structured rows such as scale tables, suffix rules, and\n            // gender-ending records. Keeping these explicit makes the generated output easier to\n            // audit than trying to encode a second generic mini-language for nested collections.\n            return member.Builder switch\n            {\n                \"harmony-ordinal-scale-array\" => CreateHarmonyOrdinalScaleArrayExpression(builderRoot),","sourceCodeStart":464,"sourceCodeEnd":500,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer.SourceGenerators/Generators/ProfileCatalogs/NumberToWordsEngineContractFactory.cs#L464-L500","documentation":"A contract member with kind 'builder' must specify a Builder name (e.g., 'billion-strategy-cardinal-scale-array') so the factory can dispatch to the correct expression generator. CreateBuilderValue checks for null Builder and throws because the switch at line 498 requires a concrete builder string.","triggerScenarios":"An EngineContractMember is constructed with kind='builder' but builder=null. CreateBuilderValue at line 480 throws. This is a generator-level contract configuration error.","commonSituations":"Adding a builder-type member to a contract and forgetting to set the Builder parameter. Changing a member kind to 'builder' without specifying which builder. Positional argument shift in the constructor dropping the builder value.","solutions":["Set the builder parameter to one of the ~40 supported builder names listed in the switch at line 498-536.","If the member should not use a builder, change its kind to a direct value kind like 'string' or 'int64'.","If a new builder is needed, add a case to the switch and implement the corresponding CreateXxx expression method."],"exampleFix":"// before\nnew EngineContractMember(\n    kind: \"builder\",\n    sourcePath: \"scales\",\n    builder: null,\n    ...)\n// after\nnew EngineContractMember(\n    kind: \"builder\",\n    sourcePath: \"scales\",\n    builder: \"billion-strategy-cardinal-scale-array\",\n    ...)","handlingStrategy":"validation","validationCode":"// Validate builder members have a builder name before generation:\nforeach (var m in contract.Members)\n    if (m.Kind == \"builder\" && string.IsNullOrEmpty(m.Builder))\n        throw new ArgumentException(\"Builder member requires a Builder name.\");","typeGuard":"static bool IsBuilderMemberValid(EngineContractMember m) =>\n    m.Kind != \"builder\" || !string.IsNullOrEmpty(m.Builder);","tryCatchPattern":null,"preventionTips":["When defining a builder-typed contract member, always set the builder parameter.","Add a contract validation pass that checks all builder members have names.","Use named arguments to prevent positional argument shifts."],"tags":["source-generator","number-to-words","contract","builder","engine-contract","build-time"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}