Humanizr/Humanizer · error · InvalidOperationException

Locale '{localeCode}.headings.{key}' must contain exactly 16

Error message

Locale '{localeCode}.headings.{key}' must contain exactly 16 entries.

What it means

The heading table for each variant must contain exactly 16 entries to match the generator's fixed-width ordinal heading slot allocation. A sequence with fewer or more entries produces an index-misaligned table, so the parser enforces the exact count.

Source

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

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

        static ImmutableArray<string> ParseHeadingSequence(SimpleYamlMapping mapping, string key, string localeCode)
        {
            if (!mapping.TryGetValue(key, out var headingValue))
            {
                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,

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Count the entries in the sequence named in the message and add or remove entries to reach exactly 16.
  2. Compare entry count against a known-good locale's corresponding block.
  3. Verify no trailing blank '- ' item or missing ordinal slot.

Example fix

# before — 15 entries (one missing)
headings:
  full:
    - Zeroth
    # ... 14 more, 15 total

# after — exactly 16
headings:
  full:
    - Zeroth
    # ... 15 more, 16 total
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) and len(val) != 16:
                print(f'{f.name}: headings.{key} has {len(val)} entries, expected 16')

Prevention

When it happens

Trigger: A locale's 'headings.full:' or 'headings.short:' sequence has any count other than 16 (e.g. 12 month names, or 7 day names, or an accidental extra entry).

Common situations: Confusing heading slots with month/day name counts; partial translation leaving placeholder entries; copy-paste introducing a duplicate or missing entry.

Related errors


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