Humanizr/Humanizer · error · InvalidOperationException

Indian scale-form number profiles require dense words for 0

Error message

Indian scale-form number profiles require dense words for 0 through 99.

What it means

Profile constructor validation: DenseUnitsMap must have at least 100 entries (words for 0 through 99). Thrown at profile instantiation when the generated/locale data supplies fewer. This is a locale-authoring defect surfaced the first time the culture's converter is built (i.e. on first ToWords/ToOrdinalWords for that culture).

Source

Thrown at src/Humanizer/Localisation/NumberToWords/IndianScaleFormNumberToWordsConverter.cs:143

    public string ZeroWord { get; } = zeroWord;
    /// <summary>Gets the word used to prefix negative numbers.</summary>
    public string NegativeWord { get; } = negativeWord;
    /// <summary>Gets the suffix appended when no terminal replacement applies.</summary>
    public string OrdinalSuffix { get; } = ordinalSuffix;
    /// <summary>Gets dense cardinal words keyed by value.</summary>
    public string[] DenseUnitsMap { get; } = ValidateDenseUnitsMap(denseUnitsMap);
    /// <summary>Gets descending Indian grouping scale rows.</summary>
    public IndianScaleForm[] Scales { get; } = ValidateScales(scales, denseUnitsMap.Length);
    /// <summary>Gets exact ordinal words keyed by value.</summary>
    public FrozenDictionary<int, string> OrdinalMap { get; } = ordinalMap ?? FrozenDictionary<int, string>.Empty;
    /// <summary>Gets terminal cardinal-token replacements used to form ordinals.</summary>
    public FrozenDictionary<string, string> OrdinalTerminalReplacements { get; } = ordinalTerminalReplacements ?? FrozenDictionary<string, string>.Empty;

    static string[] ValidateDenseUnitsMap(string[] value)
    {
        if (value.Length < 100)
        {
            throw new InvalidOperationException("Indian scale-form number profiles require dense words for 0 through 99.");
        }

        return value;
    }

    static IndianScaleForm[] ValidateScales(IndianScaleForm[] value, int denseUnitCount)
    {
        if (value.Length == 0 || value[^1].Value > denseUnitCount)
        {
            throw new InvalidOperationException("Indian scale-form number profiles require a scale value covered by the dense unit map range.");
        }

        for (var i = 0; i < value.Length; i++)
        {
            if (value[i].Value <= 0)
            {
                throw new InvalidOperationException("Indian scale-form number profiles require positive scale values.");
            }

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Report the locale bug — dense words for 0-99 are required.
  2. Use a locale/version with a complete dense unit map.
  3. If authoring, provide dense words for 0 through 99 in the locale YAML.
Defensive patterns

Strategy: try-catch

Validate before calling

// Construction-time validation throws when the converter is first resolved for the culture.
// No public pre-check; isolate converter resolution so one bad locale does not poison the process.

Try / catch

string words;
try
{
    words = value.ToWords(culture);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("dense words for 0 through 99"))
{
    // Locale-data defect; fall back to a known-good culture.
    words = value.ToWords(CultureInfo.InvariantCulture);
}

Prevention

When it happens

Trigger: First call to ToWords()/ToOrdinalWords() for an IndianScaleForm culture whose profile.denseUnitsMap has fewer than 100 elements; the constructor throws during converter resolution.

Common situations: Incomplete locale YAML providing only a partial dense map; a source-generator regression emitting a truncated map.

Related errors


AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13). Data as JSON: /api/errors/5d2718e9f3b2b7be. Report an issue: GitHub.