Humanizr/Humanizer · error · InvalidOperationException

Locale YAML root must be a mapping.

Error message

Locale YAML root must be a mapping.

What it means

The locale YAML parser expects the document root to be a mapping (key-value pairs), because each locale file is a set of feature keys. If the top-level parsed node is a sequence or scalar — for instance the file starts with a list item — the root contract is violated and parsing aborts.

Source

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

    {
        sealed class LineInfo(int indent, string content, int lineNumber)
        {
            public int Indent { get; } = indent;
            public string Content { get; } = content;
            public int LineNumber { get; } = lineNumber;
        }

        public static SimpleYamlMapping Parse(string text)
        {
            var lines = NormalizeLines(text);
            if (lines.Count == 0)
            {
                return new SimpleYamlMapping(ImmutableDictionary<string, SimpleYamlValue>.Empty.WithComparers(StringComparer.Ordinal));
            }

            var index = 0;
            var value = ParseBlock(lines, ref index, 0, rejectDuplicateKeys: false);
            return value is not SimpleYamlMapping mapping ? throw new InvalidOperationException("Locale YAML root must be a mapping.") : mapping;
        }

        static List<LineInfo> NormalizeLines(string text)
        {
            var result = new List<LineInfo>();
            var lines = text.Split(["\r\n", "\n"], StringSplitOptions.None);

            for (var lineNumber = 0; lineNumber < lines.Length; lineNumber++)
            {
                var rawLine = StripComment(lines[lineNumber]);
                if (string.IsNullOrWhiteSpace(rawLine))
                {
                    continue;
                }

                var indent = 0;
                while (indent < rawLine.Length && rawLine[indent] == ' ')
                {

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Ensure the file's top level consists of 'key: value' mapping entries (e.g. 'inherits:', 'formatter:', 'headings:').
  2. Remove any leading '- ' sequence items at column 0.
  3. Compare the file header against a known-good locale file.

Example fix

# before — root is a sequence
- inherits: en
- formatter: default

# after — root is a mapping
inherits: en
formatter: default
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 not isinstance(data, dict):
        print(f'{f.name}: YAML root must be a mapping, got {type(data).__name__}')

Prevention

When it happens

Trigger: A locale YAML file whose first non-blank, non-comment line begins with '- ' (a sequence item) or is a bare scalar, making the document root a sequence or scalar instead of a mapping.

Common situations: Accidentally prepending a list at the top of the file; truncating a file so only a fragment remains; pasting a YAML fragment that is a standalone list.

Related errors


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