Humanizr/Humanizer · error · InvalidOperationException
Builder members require a builder name.
Error message
Builder members require a builder name.
What it means
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.
Source
Thrown at src/Humanizer.SourceGenerators/Generators/ProfileCatalogs/NumberToWordsEngineContractFactory.cs:482
static string CreateNullableIntSetValue(JsonElement root, EngineContractMember member)
{
if (EngineContractUtilities.TryGetElement(root, member.SourcePath, out _))
{
return CreateNullableIntFrozenSetExpression(root, EngineContractUtilities.GetLeafPropertyName(member.SourcePath));
}
return member.MissingValue switch
{
"empty" => "FrozenSet<int>.Empty",
_ => "null"
};
}
static string CreateBuilderValue(JsonElement root, EngineContractMember member)
{
if (member.Builder is null)
{
throw new InvalidOperationException("Builder members require a builder name.");
}
if (member.Builder == "billion-strategy-cardinal-scale-array" &&
!EngineContractUtilities.TryGetElement(root, member.SourcePath, out _))
{
return CreateLegacyBillionStrategyCardinalScaleArrayExpression(root);
}
var builderRoot = string.IsNullOrWhiteSpace(member.SourcePath)
? root
: EngineContractUtilities.GetRequiredElement(root, member.SourcePath);
// Builders exist for repeated structured rows such as scale tables, suffix rules, and
// gender-ending records. Keeping these explicit makes the generated output easier to
// audit than trying to encode a second generic mini-language for nested collections.
return member.Builder switch
{
"harmony-ordinal-scale-array" => CreateHarmonyOrdinalScaleArrayExpression(builderRoot),View on GitHub (pinned to ffc2b77c0f)
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.
Example fix
// before
new EngineContractMember(
kind: "builder",
sourcePath: "scales",
builder: null,
...)
// after
new EngineContractMember(
kind: "builder",
sourcePath: "scales",
builder: "billion-strategy-cardinal-scale-array",
...) Defensive patterns
Strategy: validation
Validate before calling
// Validate builder members have a builder name before generation:
foreach (var m in contract.Members)
if (m.Kind == "builder" && string.IsNullOrEmpty(m.Builder))
throw new ArgumentException("Builder member requires a Builder name."); Type guard
static bool IsBuilderMemberValid(EngineContractMember m) =>
m.Kind != "builder" || !string.IsNullOrEmpty(m.Builder); Prevention
- 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.
When it happens
Trigger: An EngineContractMember is constructed with kind='builder' but builder=null. CreateBuilderValue at line 480 throws. This is a generator-level contract configuration error.
Common situations: 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.
Related errors
- Unexpected east-asian scale builder.
- Unsupported number-to-words builder '{member.Builder}'.
- Unsupported number-to-words contract member kind '{member.Ki
- Enum members require an enum type.
- Array-backed metric scale word contracts require a value pro
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/63a8a3dd605e41fe.
Report an issue: GitHub.