Humanizr/Humanizer · error · InvalidOperationException

Locale '{localeCode}.surfaces.number' defines unsupported pr

Error message

Locale '{localeCode}.surfaces.number' defines unsupported property '{property}'. Supported properties: words, parse, formatting.

What it means

Under `surfaces.number:` only words, parse, and formatting are allowed (CanonicalLocaleAuthoring.cs:213-217). The number surface is deliberately split so writer and parser contracts stay aligned; legacy flat keys like numberToWords/wordsToNumber are not accepted here.

Source

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

                        features["inflection"] = surfaceMapping;
                        break;

                    default:
                        break;
                }
            }

            return new LocaleDefinition(document.LocaleCode, document.VariantOf, features.ToImmutable());
        }

        static void AddNumberFeatures(
            string localeCode,
            SimpleYamlMapping numberSurface,
            ImmutableDictionary<string, SimpleYamlValue>.Builder features)
        {
            foreach (var property in numberSurface.Values.Keys.Where(static property => property is not ("words" or "parse" or "formatting")))
            {
                throw new InvalidOperationException(
                    $"Locale '{localeCode}.surfaces.number' defines unsupported property '{property}'. Supported properties: words, parse, formatting.");
            }

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

                features["numberToWords"] = wordsMapping;
            }

            if (numberSurface.TryGetValue("parse", out var parseValue))
            {
                if (parseValue is not SimpleYamlMapping parseMapping)
                {

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Move spellout data under `number.words`, parser data under `number.parse`, decimal separators under `number.formatting`.
  2. Remove any other property.
  3. Rebuild.

Example fix

# before
surfaces:
  number:
    numberToWords: {...}
# after
surfaces:
  number:
    words: {...}
Defensive patterns

Strategy: validation

Validate before calling

import yaml, sys
ALLOWED = {'words','parse','formatting'}
doc = yaml.safe_load(open(sys.argv[1], encoding='utf-8'))
num = (doc.get('surfaces') or {}).get('number')
if isinstance(num, dict):
    bad = [k for k in num if k not in ALLOWED]
    assert not bad, f'unsupported surfaces.number keys: {bad}'

Prevention

When it happens

Trigger: Putting `numberToWords:` or `wordsToNumber:` directly under surfaces.number, or any typo (word:, parseing:).

Common situations: Migrating an old locale and leaving legacy number keys under the new number surface.

Related errors


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