Humanizr/Humanizer · error · InvalidOperationException

Locale '{localeCode}.headings.{key}[{index}]' must be a scal

Error message

Locale '{localeCode}.headings.{key}[{index}]' must be a scalar.

What it means

Each entry in a headings sequence must be a YAML scalar (a plain or quoted string). If an entry is itself a nested mapping or sub-sequence, the parser cannot extract a string heading and rejects the specific entry by its index.

Source

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

                throw new InvalidOperationException($"Locale '{localeCode}.headings' must define '{key}'.");
            }

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

            if (sequence.Items.Length != 16)
            {
                throw new InvalidOperationException($"Locale '{localeCode}.headings.{key}' must contain exactly 16 entries.");
            }

            var headings = ImmutableArray.CreateBuilder<string>(16);
            for (var index = 0; index < sequence.Items.Length; index++)
            {
                if (sequence.Items[index] is not SimpleYamlScalar scalar)
                {
                    throw new InvalidOperationException($"Locale '{localeCode}.headings.{key}[{index}]' must be a scalar.");
                }

                headings.Add(scalar.Value);
            }

            return headings.MoveToImmutable();
        }

        static T? TryResolveLocalePart<T>(
            string localeCode,
            ImmutableArray<Diagnostic>.Builder diagnostics,
            Func<string, ImmutableDictionary<string, SimpleYamlValue>, T?> resolver,
            ImmutableDictionary<string, SimpleYamlValue> features)
            where T : class
        {
            try
            {
                return resolver(localeCode, features);

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Inspect the entry at the 0-based index named in the message and flatten it to a scalar string.
  2. Remove any nested key-value structure from that list item.
  3. Re-validate the whole sequence for similar structural issues at other indices.

Example fix

# before — entry 0 is a mapping
headings:
  full:
    - name: January

# after — entry 0 is a scalar
headings:
  full:
    - January
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 isinstance(data.get('headings'), dict):
        for key in ('full', 'short'):
            val = data['headings'].get(key)
            if isinstance(val, list):
                for i, item in enumerate(val):
                    if not isinstance(item, str):
                        print(f'{f.name}: headings.{key}[{i}] must be a scalar string, got {type(item).__name__}')

Prevention

When it happens

Trigger: One of the items under 'headings.full:' or 'headings.short:' is a mapping or nested list, e.g. '- full: January' instead of '- January'. The {index} placeholder identifies the offending position.

Common situations: Indentation drift causing a sub-key to attach as a list item; copy-pasting structured data into a flat string slot; leftover debugging nodes.

Related errors


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