Humanizr/Humanizer · critical · InvalidOperationException
Linked-vigesimal parser profiles require descending scales.
Error message
Linked-vigesimal parser profiles require descending scales.
What it means
This InvalidOperationException is thrown by LinkedVigesimalWordsToNumberProfile.ValidateScales (called from the profile constructor) when two adjacent scale rows are not strictly descending — i.e. when a later (smaller-position) scale has a value greater than or equal to the previous (larger) scale. The linked-vigesimal parser walks scales from largest to smallest and relies on this ordering to decompose numbers. The check fires at profile construction time, surfacing during locale registry initialization.
Source
Thrown at src/Humanizer/Localisation/WordsToNumber/LinkedVigesimalWordsToNumberConverter.cs:498
static string[] Tokenize(string value) =>
value.Split(' ', StringSplitOptions.RemoveEmptyEntries);
static string Normalize(string value) =>
string.Join(" ", value.Trim().ToLowerInvariant().Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries));
static LinkedVigesimalScale[] ValidateScales(LinkedVigesimalScale[] value)
{
for (var i = 0; i < value.Length; i++)
{
if (value[i].Value <= 0)
{
throw new InvalidOperationException("Linked-vigesimal parser profiles require positive scale values.");
}
if (i > 0 && value[i - 1].Value <= value[i].Value)
{
throw new InvalidOperationException("Linked-vigesimal parser profiles require descending scales.");
}
}
return value;
}
}
/// <summary>Pre-tokenized linked-vigesimal scale phrase.</summary>
readonly record struct TokenizedLinkedVigesimalScale(long Value, string[] OneTokens, string[] OneWithRemainderTokens, string[] NameTokens, string[] NameWithRemainderTokens);View on GitHub (pinned to ffc2b77c0f)
Solutions
- Order scale values in strictly descending order in the locale YAML (e.g. 8000, 400, 20).
- Regenerate the locale source from corrected YAML using the project's source generator.
- Verify no duplicate scale values exist in the locale's scale list.
- Add a CI test that constructs each locale profile to catch ordering violations early.
Example fix
// before (locale YAML scales) // - value: 20 // - value: 400 # out of order // after // - value: 400 // - value: 20
Defensive patterns
Strategy: validation
Validate before calling
// For locale authors: validate scale ordering before registration
static bool ScalesAreDescending(long[] scales)
{
for (var i = 1; i < scales.Length; i++)
{
if (scales[i - 1] <= scales[i])
return false;
}
return true;
} Try / catch
try
{
var converter = Configurator.GetWordsToNumberConverter(culture);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("descending scales"))
{
converter = Configurator.GetWordsToNumberConverter(fallbackCulture);
} Prevention
- Order scale values strictly descending in locale YAML (e.g. 8000, 400, 20).
- Ensure no duplicate scale values exist.
- Run the locale test suite after any YAML or generator change.
- Add CI tests that construct each locale profile to catch ordering violations.
When it happens
Trigger: Constructing a LinkedVigesimalWordsToNumberProfile with a scales array where any scale[i].Value is greater than or equal to scale[i-1].Value. This arises from locale YAML data with misordered or duplicate scale values.
Common situations: Editing locale YAML and accidentally swapping scale rows or duplicating a value; a locale generator sorting scales incorrectly; forking a locale and reordering entries; a merge conflict that scrambled scale ordering.
Related errors
- Linked-vigesimal parser profiles require positive scale valu
- Linked-vigesimal parser profiles require descending scales w
- A dedicated 71 spelling is required when specialSeventyOneEn
- Cannot extract negative prefix for culture '{culture.Name}'
- '{path}.units' must explicitly define '{unitName}'.
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/faa895f5cd9f1a8f.
Report an issue: GitHub.