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
- Rewrite surfaces.ordinal.numeric as a mapping (the ordinalizer rule table expected by the generator).
- 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.
- 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
- Model the ordinalizer as a mapping of rules, never a boolean toggle.
- Copy the 'numeric' block from a reference locale and translate it.
- Build after edits to confirm the type guard passes.
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
- Locale '{localeCode}.surfaces.ordinal' defines unsupported p
- Locale '{localeCode}.surfaces.ordinal.date' must be a mappin
- Locale '{localeCode}.surfaces.ordinal.dateOnly' must be a ma
- Locale '{localeCode}.{path}' defines duplicate numeric minut
- Locale '{localeCode}.{path}.{key}' must be a string.
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/594e327d27c1cdc6.
Report an issue: GitHub.