Humanizr/Humanizer · error · InvalidOperationException
Locale '{localeCode}' defines unsupported top-level property
Error message
Locale '{localeCode}' defines unsupported top-level property '{property}'. Supported properties: {string.Join(", ", SupportedTopLevelNames)}. What it means
During the source-generator build, CanonicalLocaleAuthoring.Parse rejects any top-level YAML key not in {locale, variantOf, surfaces} (CanonicalLocaleAuthoring.cs:70-75). The canonical schema is intentionally tiny; legacy flat keys (inherits, collectionFormatter, etc.) are rejected here and must be migrated first.
Source
Thrown at src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs:72
static readonly string[] FormatterGrammarPropertyNames =
[
"pluralRule",
"casePluralRule",
"dataUnitPluralRule",
"dataUnitNonIntegralForm",
"prepositionMode",
"secondaryPlaceholderMode",
"timeUnitGenders"
];
internal static CanonicalLocaleDocument Parse(string localeCode, string fileText)
{
var root = SimpleYamlParser.Parse(fileText);
foreach (var property in root.Values.Keys.Where(static property => !SupportedTopLevelNames.Contains(property, StringComparer.Ordinal)))
{
throw new InvalidOperationException(
$"Locale '{localeCode}' defines unsupported top-level property '{property}'. " +
$"Supported properties: {string.Join(", ", SupportedTopLevelNames)}.");
}
var declaredLocale = root.GetScalar("locale")
?? throw new InvalidOperationException(
$"Locale '{localeCode}' must define required top-level property 'locale'.");
if (!string.Equals(localeCode, declaredLocale, StringComparison.Ordinal))
{
throw new InvalidOperationException(
$"Locale '{declaredLocale}' must match file locale '{localeCode}'.");
}
var variantOf = root.GetScalar("variantOf");
SimpleYamlMapping surfaces;
if (!root.TryGetValue("surfaces", out var surfacesValue))View on GitHub (pinned to ffc2b77c0f)
Solutions
- Read the message: it names the offending property and lists allowed names.
- If the property is legacy (inherits, formatter, numberToWords...), run LegacyLocaleMigration.ConvertToCanonicalYaml to migrate it, or move it under the correct surface.
- Fix typos: surface -> surfaces.
- Remove any genuinely unwanted top-level key.
Example fix
# before
locale: "fr"
inherit: "en"
surfaces:
clock: {}
# after
locale: "fr"
variantOf: "en"
surfaces:
clock: {} Defensive patterns
Strategy: validation
Validate before calling
# Quick YAML lint: allowed top-level keys only
import yaml, sys
ALLOWED = {'locale','variantOf','surfaces'}
doc = yaml.safe_load(open(sys.argv[1], encoding='utf-8'))
bad = [k for k in doc if k not in ALLOWED]
assert not bad, f'unsupported top-level keys: {bad}' 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: A locale YAML file under src/Humanizer/Locales contains a key outside locale/variantOf/surfaces — e.g. a typo (surface:), a leftover legacy key (inherits:, formatter: at top level), or a copied block pasted at the wrong indentation.
Common situations: Copying an old pre-canonical locale file; typoing 'surfaces' as 'surface'; merging a PR that uses a renamed property.
Related errors
- Locale '{localeCode}.surfaces' defines unsupported surface '
- Locale '{localeCode}.surfaces.number' defines unsupported pr
- Locale '{localeCode}' must define required top-level propert
- Locale '{declaredLocale}' must match file locale '{localeCod
- Locale '{localeCode}' must define required top-level propert
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/e7bedddba9bdb927.
Report an issue: GitHub.