Humanizr/Humanizer · error · InvalidOperationException

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

Error message

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

What it means

The 'grammar' feature must be a YAML mapping (object) because it contains keyed grammar configuration such as cases and genders. A scalar or sequence value cannot supply those sub-keys, so the resolver rejects it.

Source

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

                        kind: scalar.Value,
                        argument: null,
                        profileName: null,
                        profileRoot: default,
                        usesGeneratedProfile: false),
                    SimpleYamlMapping mapping => CreateMappedFeature(localeCode, featureName, mapping),
                    _ => throw new InvalidOperationException(
                        $"Feature '{featureName}' in locale '{localeCode}' must be a scalar or mapping.")
                };
        }

        static SimpleYamlMapping? ResolveGrammar(
            string localeCode,
            ImmutableDictionary<string, SimpleYamlValue> features)
        {
            return !features.TryGetValue("grammar", out var grammarValue)
                ? 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.");
        }

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Change the 'grammar:' value to a mapping with the expected sub-keys.
  2. Reference an existing locale with grammar (e.g. 'ru.yml', 'ar.yml') for the correct structure.
  3. If the locale does not need grammar rules, remove the 'grammar:' key entirely rather than setting a placeholder.

Example fix

# before
grammar: slavic

# after
grammar:
  cases:
    nominative: 0
    genitive: 1
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 'grammar' in data:
        if not isinstance(data['grammar'], dict):
            print(f'{f.name}: grammar must be a mapping, got {type(data["grammar"]).__name__}')

Prevention

When it happens

Trigger: A locale file sets 'grammar:' to a bare scalar (e.g. 'grammar: latin') or to a sequence instead of a nested mapping of grammar rules.

Common situations: Misunderstanding the grammar schema; copy-pasting a scalar feature value into the grammar slot; truncating a grammar block during editing.

Related errors


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