Humanizr/Humanizer · error · InvalidOperationException

Locale '{localeCode}.surfaces.number.formatting' must be a m

Error message

Locale '{localeCode}.surfaces.number.formatting' must be a mapping, not a scalar or sequence.

What it means

`surfaces.number.formatting` must be a mapping of decimalSeparator/negativeSign/groupSeparator (CanonicalLocaleAuthoring.cs:241-247) before its contents are validated by ValidateNumberFormattingBlock.

Source

Thrown at src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs:245

                features["numberToWords"] = wordsMapping;
            }

            if (numberSurface.TryGetValue("parse", out var parseValue))
            {
                if (parseValue is not SimpleYamlMapping parseMapping)
                {
                    throw new InvalidOperationException(
                        $"Locale '{localeCode}.surfaces.number.parse' must be a mapping, not a scalar or sequence.");
                }

                features["wordsToNumber"] = parseMapping;
            }

            if (numberSurface.TryGetValue("formatting", out var fmtValue))
            {
                if (fmtValue is not SimpleYamlMapping fmtMapping)
                {
                    throw new InvalidOperationException(
                        $"Locale '{localeCode}.surfaces.number.formatting' must be a mapping, not a scalar or sequence.");
                }

                ValidateNumberFormattingBlock(localeCode, fmtMapping);
                features["numberFormatting"] = fmtMapping;
            }
        }

        static SimpleYamlMapping NormalizeClockSurface(string localeCode, SimpleYamlMapping clockSurface)
        {
            if (clockSurface.DuplicateKeys.Contains("minuteWordsMap"))
            {
                throw new InvalidOperationException(
                    $"Locale '{localeCode}.surfaces.clock.minuteWordsMap' defines duplicate entries; choose either the dense or sparse form.");
            }

            if (!clockSurface.TryGetValue("minuteWordsMap", out var minuteWordsMap))
            {

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Use a mapping: `formatting:` then `decimalSeparator: ","`.
  2. Provide at least one of the three allowed keys (a later check requires >=1).
  3. Rebuild.

Example fix

# before
surfaces:
  number:
    formatting: ","
# after
surfaces:
  number:
    formatting:
      decimalSeparator: ","
Defensive patterns

Strategy: validation

Validate before calling

import yaml, sys
doc = yaml.safe_load(open(sys.argv[1], encoding='utf-8'))
f = ((doc.get('surfaces') or {}).get('number') or {}).get('formatting')
if f is not None:
    assert isinstance(f, dict), 'surfaces.number.formatting must be a mapping'

Prevention

When it happens

Trigger: Writing `formatting: ","` or a list under surfaces.number.

Common situations: Trying to set just a decimal separator as a scalar.

Related errors


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