Humanizr/Humanizer · error · InvalidOperationException

Locale '{localeCode}' must define required top-level propert

Error message

Locale '{localeCode}' must define required top-level property 'surfaces'.

What it means

A base locale (no variantOf) must define `surfaces:` (CanonicalLocaleAuthoring.cs:89-96). Only a pure variant — one declaring `variantOf:` — may omit surfaces and inherit everything. This prevents a culture being registered with no localizable content.

Source

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

            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))
            {
                if (string.IsNullOrWhiteSpace(variantOf))
                {
                    throw new InvalidOperationException(
                        $"Locale '{localeCode}' must define required top-level property 'surfaces'.");
                }

                surfaces = new SimpleYamlMapping(
                    ImmutableDictionary<string, SimpleYamlValue>.Empty.WithComparers(StringComparer.Ordinal));
            }
            else
            {
                surfaces = surfacesValue is SimpleYamlMapping surfacesMapping
                    ? surfacesMapping
                    : throw new InvalidOperationException($"Locale '{localeCode}.surfaces' must be a mapping.");
            }

            foreach (var surface in surfaces.Values)
            {
                if (!SupportedSurfaceNames.Contains(surface.Key, StringComparer.Ordinal))
                {
                    throw new InvalidOperationException(

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Add a `surfaces:` mapping (even `surfaces: {}` is valid for a first stub) if the locale is standalone.
  2. If the locale only overrides a parent, add `variantOf: "<parent>"` and omit surfaces.
  3. Move any surface content you removed back under surfaces.

Example fix

# before (standalone locale)
locale: "de"
# after
locale: "de"
surfaces:
  clock: {}
Defensive patterns

Strategy: validation

Validate before calling

import yaml, sys
doc = yaml.safe_load(open(sys.argv[1], encoding='utf-8'))
is_variant = bool(doc.get('variantOf'))
assert is_variant or 'surfaces' in doc, 'a non-variant locale must define surfaces:'

Prevention

When it happens

Trigger: A new top-level locale file has `locale:` but no `surfaces:` block and no `variantOf:`.

Common situations: Starting a brand-new locale and forgetting the surfaces block; stripping content during a refactor.

Related errors


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