Humanizr/Humanizer · error · ArgumentException

Decimal marker must not be empty.

Error message

Decimal marker must not be empty.

What it means

LocalizedWordsToDecimalNumberConverter's constructor throws this ArgumentException at line 28 when decimalMarker normalizes to an empty string. The decimal grammar needs exactly one locale-specific marker to split integer and fractional parts, so an empty marker is unrecoverable. The converter is internal and built from locale data, so an empty marker is a locale-authoring defect.

Source

Thrown at src/Humanizer/Localisation/WordsToNumber/LocalizedWordsToDecimalNumberConverter.cs:28

    readonly CompareInfo compareInfo;
    readonly string decimalMarker;
    readonly FractionalDigit[] fractionalDigits;
    readonly IWordsToNumberConverter integerConverter;
    readonly bool allowsJoinedTokens;
    readonly bool allowsEnglishOverflowComposition;
    readonly NegativeAffix[] negativePrefixes;
    readonly NegativeAffix[] negativeSuffixes;

    public LocalizedWordsToDecimalNumberConverter(
        CultureInfo culture,
        string decimalMarker,
        string[] negativePrefixes,
        string[] negativeSuffixes)
    {
        compareInfo = culture.CompareInfo;
        this.decimalMarker = NormalizeWhitespace(decimalMarker);
        if (this.decimalMarker.Length == 0)
            throw new ArgumentException("Decimal marker must not be empty.", nameof(decimalMarker));

        integerConverter = Configurator.GetWordsToNumberConverter(culture);
        allowsJoinedTokens = integerConverter is EastAsianPositionalWordsToNumberConverter;
        allowsEnglishOverflowComposition =
            string.Equals(culture.TwoLetterISOLanguageName, "en", StringComparison.OrdinalIgnoreCase);
        this.negativePrefixes = NormalizePrefixes(negativePrefixes);
        this.negativeSuffixes = NormalizeSuffixes(negativeSuffixes);
        fractionalDigits = CreateFractionalDigits(culture);
    }

    internal string DecimalMarker => decimalMarker;

    /// <inheritdoc />
    public decimal Convert(string words)
    {
        ArgumentNullException.ThrowIfNull(words);

        if (!TryConvert(words, out var parsedValue, out var unrecognizedNumber))

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Provide a non-empty locale-specific decimal marker (e.g. 'point', 'virgule', the localized 'and'-style token) in the locale decimal configuration.
  2. Regenerate locale source and run the locale's decimal word tests.
  3. Add a construction assertion in locale tests verifying the converter builds for that culture.

Example fix

// before (locale decimal config)
decimalMarker: ""
// after
decimalMarker: "point",  // localized marker for splitting integer/fractional words
Defensive patterns

Strategy: validation

Validate before calling

// Authoring-time guard: confirm the decimal converter builds for the culture.
var decimalConverter = Configurator.GetWordsToDecimalNumberConverter(targetCulture);
Assert.False(decimalConverter is UnsupportedWordsToDecimalNumberConverter);

Prevention

When it happens

Trigger: A locale's decimal-word configuration supplies an empty or whitespace-only decimal marker; the marker value is stripped to empty by NormalizeWhitespace; or the generator wires an empty marker. Construction happens lazily when ToDecimalNumber/TryToDecimalNumber first resolves the culture.

Common situations: A new locale with decimal words added but its decimal marker key left blank; a YAML typo that yields an empty string; regenerating after a marker rename.

Related errors


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