Humanizr/Humanizer · error · InvalidOperationException
Scale-leading compound parser profiles require descending sc
Error message
Scale-leading compound parser profiles require descending scales where each larger scale is divisible by the next smaller scale.
What it means
ScaleLeadingCompoundWordsToNumberConverter.GetMaximumCountForScale throws this InvalidOperationException at line 298 when adjacent scale values are not strictly descending with the larger evenly divisible by the smaller. The scale-leading grammar multiplies counts against scales, so a non-divisible or non-descending ladder makes the math ambiguous. This is a runtime invariant check on profile data, so it indicates a misconfigured locale profile rather than bad user input.
Source
Thrown at src/Humanizer/Localisation/WordsToNumber/ScaleLeadingCompoundWordsToNumberConverter.cs:298
return true;
}
parsedValue = default;
return false;
}
ulong GetMaximumCountForScale(int scaleIndex)
{
if (scaleIndex == 0)
{
return ulong.MaxValue / (ulong)profile.Scales[scaleIndex].Value;
}
var previous = (ulong)profile.Scales[scaleIndex - 1].Value;
var current = (ulong)profile.Scales[scaleIndex].Value;
if (previous <= current || previous % current != 0)
{
throw new InvalidOperationException("Scale-leading compound parser profiles require descending scales where each larger scale is divisible by the next smaller scale.");
}
return previous / current - 1UL;
}
bool TryParseOrdinalCandidate(string originalCandidate, string strippedCandidate, bool negative, out long parsedValue)
{
if (TryParseOrdinalCandidate(originalCandidate, negative, out parsedValue))
{
return true;
}
return !string.Equals(originalCandidate, strippedCandidate, StringComparison.Ordinal) &&
TryParseOrdinalCandidate(strippedCandidate, negative, out parsedValue);
}
bool TryParseOrdinalCandidate(string candidate, bool negative, out long parsedValue)
{View on GitHub (pinned to ffc2b77c0f)
Solutions
- Fix the locale's scale ladder so each scale is strictly smaller than the previous and the previous is divisible by it.
- Run the locale's words-to-number tests to confirm the corrected ladder parses correctly.
- If you need non-divisible scales, that grammar is not supported here; use a different converter family.
Example fix
// before (profile scales) Scales: [ 1000000, 1000, 100, 60 ] // 100 % 60 != 0 -> throws // after Scales: [ 1000000, 1000, 100 ] // 1000 % 100 == 0 -> ok
Defensive patterns
Strategy: validation
Validate before calling
// Authoring guard: verify the scale ladder is strictly descending & divisible.
static bool ScalesAreValid(long[] scales)
{
for (int i = 0; i < scales.Length; i++)
{
if (scales[i] <= 0) return false;
if (i > 0 && (scales[i - 1] <= scales[i] || scales[i - 1] % scales[i] != 0))
return false;
}
return true;
} Prevention
- Author scale-leading ladders as strictly descending with each larger divisible by the next (e.g. 1e6, 1e3, 1e2).
- Add locale tests that parse representative values after editing scales.
- Do not use mixed non-divisible radix here; pick a different converter family.
- Report as a locale-data bug if encountered as an end user.
When it happens
Trigger: A ScaleLeadingCompoundWordsToNumberProfile whose Scales array is not strictly descending or not cleanly divisible (e.g. [..., 1000, 100, 60] where 100 is not divisible by 60). It fires during a parse call that reaches that scale index.
Common situations: Editing a scale-leading locale's scale ladder; a typo making a larger scale smaller than the next; using mixed radix (e.g. 60/24 time-like scales) that violates divisibility; generator output from malformed YAML.
Related errors
- Scale-leading compound parser profiles require positive scal
- Teen prefix cannot be empty.
- Decimal marker must not be empty.
- Unrecognized number word: {unrecognizedWord}
- Locale '{localeCode}' defines unsupported top-level property
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/56e84e8006beb8cd.
Report an issue: GitHub.