Humanizr/Humanizer · critical · InvalidOperationException

Locale '{localeCode}.surfaces.ordinal.numeric' must be a map

Error message

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

What it means

Thrown by AddOrdinalFeatures when surfaces.ordinal.numeric is present but is not a YAML mapping. The numeric ordinal surface (ordinalizer) is itself a map of rules/keys, so a scalar or sequence value is rejected at build time.

Source

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

            }
        }

        static void AddOrdinalFeatures(
            string localeCode,
            SimpleYamlMapping ordinalSurface,
            ImmutableDictionary<string, SimpleYamlValue>.Builder features)
        {
            foreach (var property in ordinalSurface.Values.Keys.Where(static property => property is not ("numeric" or "date" or "dateOnly")))
            {
                throw new InvalidOperationException(
                    $"Locale '{localeCode}.surfaces.ordinal' defines unsupported property '{property}'. Supported properties: numeric, date, dateOnly.");
            }

            if (ordinalSurface.TryGetValue("numeric", out var numericValue))
            {
                if (numericValue is not SimpleYamlMapping numericMapping)
                {
                    throw new InvalidOperationException(
                        $"Locale '{localeCode}.surfaces.ordinal.numeric' must be a mapping, not a scalar or sequence.");
                }

                features["ordinalizer"] = numericMapping;
            }

            if (ordinalSurface.TryGetValue("date", out var dateValue))
            {
                if (dateValue is not SimpleYamlMapping dateMapping)
                {
                    throw new InvalidOperationException(
                        $"Locale '{localeCode}.surfaces.ordinal.date' must be a mapping, not a scalar or sequence.");
                }

                features["dateToOrdinalWords"] = dateMapping;
            }

            if (ordinalSurface.TryGetValue("dateOnly", out var dateOnlyValue))

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Rewrite surfaces.ordinal.numeric as a mapping (the ordinalizer rule table expected by the generator).
  2. If unsure of the required shape, copy the 'numeric' block from an existing full locale (e.g. src/Humanizer/Locales/en.yml) and translate it.
  3. Rebuild to confirm the ordinal surface type check passes.

Example fix

# before
ordinal:
  numeric: true
# after
ordinal:
  numeric:
    1: st
    2: nd
    3: rd
Defensive patterns

Strategy: validation

Validate before calling

# Ensure surfaces.ordinal.numeric is a mapping, not a scalar/sequence.
# YAML lint: 'numeric:' must be followed by an indented key/value block.

Prevention

When it happens

Trigger: A locale YAML writes 'numeric: true' or 'numeric: [first, second]' instead of a key/value mapping. The type guard at CanonicalLocaleAuthoring.cs:414-418 fails because numericValue is not a SimpleYamlMapping.

Common situations: Using a boolean toggle to enable ordinalization; pasting an array of ordinal words; mis-indenting so the mapping becomes a scalar.

Related errors


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