Humanizr/Humanizer · error · InvalidOperationException
Billion-word cardinal strategy requires a singular billion w
Error message
Billion-word cardinal strategy requires a singular billion word.
What it means
Thrown when a locale's cardinal scale declares billionStrategy: 'billion-word' but omits the billionSingularWord property. The generator builds a BillionStrategyCardinalScale[] that needs an explicit singular billion term; without it the generated converter would lack a word for 1,000,000,000. It is a schema-completeness check keyed off the strategy value.
Source
Thrown at src/Humanizer.SourceGenerators/Common/GenerationHelpers.cs:736
builder.Append(')');
first = false;
}
builder.Append(" }");
return builder.ToString();
}
static string CreateLegacyBillionStrategyCardinalScaleArrayExpression(JsonElement cardinalElement)
{
var millionScale = $"new(1000000UL, {QuoteLiteral(GetRequiredString(cardinalElement, "millionSingularWord"))}, {QuoteLiteral(GetRequiredString(cardinalElement, "millionPluralWord"))})";
if (GetRequiredString(cardinalElement, "billionStrategy") != "billion-word")
{
return $"new BillionStrategyCardinalScale[] {{ {millionScale} }}";
}
var billionSingular = GetOptionalString(cardinalElement, "billionSingularWord")
?? throw new InvalidOperationException("Billion-word cardinal strategy requires a singular billion word.");
var billionPlural = GetOptionalString(cardinalElement, "billionPluralWord")
?? throw new InvalidOperationException("Billion-word cardinal strategy requires a plural billion word.");
return $"new BillionStrategyCardinalScale[] {{ new(1000000000UL, {QuoteLiteral(billionSingular)}, {QuoteLiteral(billionPlural)}), {millionScale} }}";
}
static string CreateContractedOneScaleArrayExpression(JsonElement arrayElement)
{
if (arrayElement.ValueKind != JsonValueKind.Array)
{
throw new InvalidOperationException("Expected JSON array.");
}
var builder = new StringBuilder("new ContractedOneScaleNumberToWordsConverter.Scale[] { ");
var first = true;
foreach (var item in arrayElement.EnumerateArray())
{
if (item.ValueKind != JsonValueKind.Object)View on GitHub (pinned to ffc2b77c0f)
Solutions
- In the offending locale YAML under numberToWords cardinal, add a 'billionSingularWord' key with the singular billion term (e.g. billionSingularWord: 'un milliard').
- If the locale uses the thousand-millions scale instead, set billionStrategy to 'thousand-millions' so no billion word is required.
- Cross-check against a known billion-word locale (en.yml, fr.yml) for the exact key names and placement.
Example fix
# before cardinal: billionStrategy: 'billion-word' millionSingularWord: 'milhão' # after cardinal: billionStrategy: 'billion-word' billionSingularWord: 'mil milhões' billionPluralWord: 'mil milhões' millionSingularWord: 'milhão'
Defensive patterns
Strategy: validation
Validate before calling
# In the locale YAML, before setting billionStrategy: 'billion-word', # confirm both keys exist. Quick check with ripgrep: # rg -A2 "billionStrategy: 'billion-word'" src/Humanizer/Locales/<code>.yml # Ensure 'billionSingularWord' appears in the same cardinal block.
Prevention
- When switching billionStrategy to 'billion-word', add billionSingularWord and billionPluralWord in the same commit.
- Mirror the en.yml or fr.yml cardinal block for exact key names and placement.
- Build locally after locale changes so the generator validates the strategy/word pair.
When it happens
Trigger: A locale YAML sets numberToWords cardinal.billionStrategy to 'billion-word' (vs 'thousand-millions' or 'thousandth-millionth') but does not supply a parallel billionSingularWord string. The check runs in CreateLegacyBillionStrategyCardinalScaleArrayExpression during code generation.
Common situations: A contributor copies an existing billion-word locale (e.g. en, fr) and deletes or renames the billionSingularWord key, or switches billionStrategy from another value to 'billion-word' without adding the singular/plural word pair. Surfaces as a generator failure during dotnet build.
Related errors
- Billion-word cardinal strategy requires a plural billion wor
- Property '{propertyName}' must be a string, array, or mappin
- Property '{propertyName}' must be a mapping.
- Expected JSON array or mapping.
- Inverted tens token '{property.Name}' must map to an integer
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/a2d9ed867748286d.
Report an issue: GitHub.