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
- Change the 'grammar:' value to a mapping with the expected sub-keys.
- Reference an existing locale with grammar (e.g. 'ru.yml', 'ar.yml') for the correct structure.
- 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 adding grammar rules, always nest sub-keys under 'grammar:' as a mapping.
- Remove the grammar key entirely if the locale has no grammar data rather than leaving a scalar.
- Reference 'ru.yml' or 'ar.yml' for the correct grammar mapping structure.
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
- Phrase section '{path}' must be a mapping.
- Phrase section '{path}' defines unsupported property '{key}'
- Feature '{featureName}' in locale '{localeCode}' must be a s
- Locale '{localeCode}.phrases' must be a mapping.
- Locale '{localeCode}.headings' must be a mapping.
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/cfb15c79aa9dc8c8.
Report an issue: GitHub.