Humanizr/Humanizer · error · InvalidOperationException

Locale '{localeCode}.phrases' must be a mapping.

Error message

Locale '{localeCode}.phrases' must be a mapping.

What it means

The 'phrases' feature holds localized phrase templates as a mapping keyed by phrase identifier. Only a YAML mapping is valid here; a scalar or sequence cannot represent keyed phrase entries, so the phrase catalog resolver throws.

Source

Thrown at src/Humanizer.SourceGenerators/Common/LocaleYamlCatalog.cs:773

                ? null
                : grammarValue as SimpleYamlMapping
                ?? throw new InvalidOperationException($"Locale '{localeCode}.grammar' must be a mapping.");
        }

        static LocalePhraseCatalog? ResolvePhraseCatalog(
            string localeCode,
            ImmutableDictionary<string, SimpleYamlValue> features)
        {
            var preserveDurationCaseForms =
                features.TryGetValue("formatter", out var formatterValue) &&
                formatterValue is SimpleYamlMapping formatter &&
                formatter.GetScalar("casePluralRule") is not null;

            return !features.TryGetValue("phrases", out var phraseValue)
                ? null
                : phraseValue is SimpleYamlMapping mapping
                ? LocalePhraseNormalization.Create(localeCode, mapping, preserveDurationCaseForms)
                : throw new InvalidOperationException($"Locale '{localeCode}.phrases' must be a mapping.");
        }

        static HeadingSet? ResolveHeadings(
            string localeCode,
            ImmutableDictionary<string, SimpleYamlValue> features)
        {
            if (!features.TryGetValue("headings", out var headingValue))
            {
                return null;
            }

            if (headingValue is not SimpleYamlMapping mapping)
            {
                throw new InvalidOperationException($"Locale '{localeCode}.headings' must be a mapping.");
            }

            foreach (var property in mapping.Values.Keys.Where(static property => property is not ("full" or "short")))
            {

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Restructure the 'phrases:' value as a mapping where each key is a phrase identifier and each value is the localized template.
  2. Remove the 'phrases:' key if the locale has no phrase data.
  3. Validate indentation so phrase entries nest under the mapping, not as list items.

Example fix

# before
phrases:
  - Hello

# after
phrases:
  greeting: Hello
Defensive patterns

Strategy: validation

Validate before calling

import yaml, pathlib
locales_dir = pathlib.Path('src/Humanizer/Locales')
for f in locales_dir.rglob('*.yml'):
    data = yaml.safe_load(f.read_text())
    if isinstance(data, dict) and 'phrases' in data:
        if not isinstance(data['phrases'], dict):
            print(f'{f.name}: phrases must be a mapping, got {type(data["phrases"]).__name__}')

Prevention

When it happens

Trigger: A locale file provides 'phrases:' as a scalar string or as a YAML sequence rather than a mapping of phrase-key to content.

Common situations: Editing phrase data and accidentally flattening the structure; misindenting phrase entries so they parse as a sequence; leaving a placeholder scalar.

Related errors


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