Humanizr/Humanizer · error · InvalidOperationException

Indian scale-form number profiles require a scale value no g

Error message

Indian scale-form number profiles require a scale value no greater than the dense unit map range.

What it means

ConvertPositive decomposed the number against all scale rows and the dense unit map but produced zero parts with a remainder, meaning the scales don't cover the value's magnitude and it fell outside the dense map. The guard fires (rather than emitting an empty string) when the smallest scale value exceeds the dense unit map range, leaving an uncovered gap in the Indian scale-form profile.

Source

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

            var scaleValue = (ulong)scale.Value;
            var count = remainder / scaleValue;
            if (count == 0)
            {
                continue;
            }

            remainder %= scaleValue;
            parts.Add(FormatScale(scale, count, remainder > 0));
        }

        if (remainder > 0)
        {
            parts.Add(ConvertPositive(remainder));
        }

        if (parts.Count == 0)
        {
            throw new InvalidOperationException("Indian scale-form number profiles require a scale value no greater than the dense unit map range.");
        }

        return string.Join(" ", parts);
    }

    string FormatScale(IndianScaleForm scale, ulong count, bool hasRemainder)
    {
        var scaleWord = count == 1
            ? hasRemainder ? scale.SingularWithRemainder : scale.Singular
            : hasRemainder ? scale.PluralWithRemainder : scale.Plural;

        return count == 1 && scale.OmitOne
            ? scaleWord
            : ConvertPositive(count) + " " + scaleWord;
    }
}

/// <summary>

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Report the locale/profile bug — the scale chain has a gap above the dense unit map.
  2. Use a locale with a consistent scale chain.
  3. If authoring, ensure the smallest scale Value <= DenseUnitsMap.Length and scales descend to the dense range.
Defensive patterns

Strategy: try-catch

Validate before calling

// Scale/dense-map coverage is internal. No public pre-check; wrap Convert and fall back.

Try / catch

string words;
try
{
    words = value.ToWords(culture);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("scale value no greater than the dense unit map range"))
{
    words = value.ToWords(CultureInfo.InvariantCulture);
}

Prevention

When it happens

Trigger: value.ToWords(<indian-scale culture>) for a value that sits in the gap between the dense unit map ceiling and the smallest scale, or beyond all scales, due to a misconfigured profile (smallest scale Value > DenseUnitsMap.Length, or scales that don't chain down to the dense range).

Common situations: Locale profile where scales start above where dense words end; scales that don't descend to 100; a source-generator gap.

Related errors


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