Humanizr/Humanizer · error · ArgumentException

Unrecognized number word: {unrecognizedWord}

Error message

Unrecognized number word: {unrecognizedWord}

What it means

This ArgumentException is thrown by ContractedScaleWordsToNumberConverter.Convert (the throwing entry point) when TryConvert fails to parse the input. This converter handles Malay-style contracted scale systems where tokens like 'puluh' (tens) and 'belas' (teens) act as structural operators. The error fires when the normalized phrase contains a token absent from the locale's cardinal dictionary, meaning the phrase cannot be composed into a number.

Source

Thrown at src/Humanizer/Localisation/WordsToNumber/ContractedScaleWordsToNumberConverter.cs:27

/// walks the token stream from left to right. Contracted tens and teens such as <c>puluh</c> and
/// <c>belas</c> are interpreted as structural operators over the current accumulated value rather
/// than as plain additive words. Locale data can therefore express native high-range phrases and
/// parse them back through the same token map.
/// </summary>
class ContractedScaleWordsToNumberConverter(ContractedScaleWordsToNumberProfile profile) : GenderlessWordsToNumberConverter
{
    /// <summary>
    /// Immutable parser profile emitted from locale YAML. It owns the literal minus word and the
    /// cardinal token dictionary used by the state machine below.
    /// </summary>
    readonly ContractedScaleWordsToNumberProfile profile = profile;

    /// <inheritdoc />
    public override long Convert(string words)
    {
        if (!TryConvert(words, out var parsedValue, out var unrecognizedWord))
        {
            throw new ArgumentException($"Unrecognized number word: {unrecognizedWord}");
        }

        return parsedValue;
    }

    /// <inheritdoc />
    public override bool TryConvert(string words, out long parsedValue) =>
        TryConvert(words, out parsedValue, out _);

    /// <inheritdoc />
    public override bool TryConvert(string words, out long parsedValue, out string? unrecognizedWord)
    {
        if (string.IsNullOrWhiteSpace(words))
        {
            throw new ArgumentException("Input words cannot be empty.");
        }

        var normalized = Normalize(words);

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Use TryToNumber(words, out value, culture, out unrecognizedWord) for user-facing input so parse failures return false instead of throwing.
  2. Validate that the culture matches the language of the input words.
  3. Normalize or constrain input to the locale's known vocabulary before parsing.
  4. Inspect the unrecognizedWord output to guide the user to correct the input.

Example fix

// before
long value = text.ToNumber(new CultureInfo("ms"));

// after
if (!text.TryToNumber(out var value, new CultureInfo("ms"), out var bad))
    Console.WriteLine($"Could not parse; unknown token: {bad}");
Defensive patterns

Strategy: try-catch

Validate before calling

bool canParse = words.TryToNumber(out var value, culture, out var unrecognized);
if (!canParse)
    Console.WriteLine($"Unknown token: {unrecognized}");

Type guard

static bool LooksLikeNumberWords(string words, CultureInfo culture) =>
    !string.IsNullOrWhiteSpace(words) && words.TryToNumber(out _, culture, out _);

Try / catch

try
{
    return words.ToNumber(culture);
}
catch (ArgumentException ex) when (ex.Message.Contains("Unrecognized number word"))
{
    return 0;
}

Prevention

When it happens

Trigger: Calling "words".ToNumber(culture) for a contracted-scale locale with a phrase containing a word not in the locale's Cardinals token map, or a structural token used in an unsupported position.

Common situations: Free-text user input fed directly to ToNumber; locale mismatch (words from a different language); a typo or non-standard spelling not covered by the locale's normalization; using a scale or teen word the locale YAML did not register.

Related errors


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