Humanizr/Humanizer · error · InvalidOperationException
Locale '{localeCode}.surfaces.number.words' must be a mappin
Error message
Locale '{localeCode}.surfaces.number.words' must be a mapping, not a scalar or sequence. What it means
`surfaces.number.words` holds the number-to-words engine description and must be a mapping (CanonicalLocaleAuthoring.cs:219-225). A scalar or sequence cannot express the engine/argument/profile structure.
Source
Thrown at src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs:223
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)
{
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))View on GitHub (pinned to ffc2b77c0f)
Solutions
- Provide `words:` as a mapping with the engine key and any arguments.
- If the locale has no spellout, omit words entirely.
- Rebuild.
Example fix
# before
surfaces:
number:
words: default
# after
surfaces:
number:
words:
engine: "english"
argument: "" Defensive patterns
Strategy: validation
Validate before calling
import yaml, sys
doc = yaml.safe_load(open(sys.argv[1], encoding='utf-8'))
words = ((doc.get('surfaces') or {}).get('number') or {}).get('words')
if words is not None:
assert isinstance(words, dict), 'surfaces.number.words must be a mapping' Prevention
- Author locales against the canonical schema; the error message lists the exact allowed names.
- Run `dotnet build src/Humanizer/Humanizer.csproj` locally so the generator reports locale errors before push.
- Copy an existing compliant locale file as your template rather than writing YAML from scratch.
When it happens
Trigger: Writing `words: "engine"` or `words: [...]` under surfaces.number.
Common situations: Porting a locale whose words block was a single string; truncating during migration.
Related errors
- Locale '{localeCode}.surfaces.number' defines unsupported pr
- Locale '{localeCode}.surfaces.number.parse' must be a mappin
- Locale '{localeCode}.surfaces.number.formatting' must be a m
- Locale '{localeCode}' defines unsupported top-level property
- Locale '{localeCode}' must define required top-level propert
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/65174db74fbe94ea.
Report an issue: GitHub.