Humanizr/Humanizer · error · InvalidOperationException

Locale '{localeCode}.{path}' must be a sequence or sparse nu

Error message

Locale '{localeCode}.{path}' must be a sequence or sparse numeric mapping.

What it means

minuteWordsMap must be either a sequence (dense) or a numeric-keyed mapping (sparse); any other shape, e.g. a bare scalar, is rejected (CanonicalLocaleAuthoring.cs:268-274).

Source

Thrown at src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs:272

        static SimpleYamlMapping NormalizeClockSurface(string localeCode, SimpleYamlMapping clockSurface)
        {
            if (clockSurface.DuplicateKeys.Contains("minuteWordsMap"))
            {
                throw new InvalidOperationException(
                    $"Locale '{localeCode}.surfaces.clock.minuteWordsMap' defines duplicate entries; choose either the dense or sparse form.");
            }

            if (!clockSurface.TryGetValue("minuteWordsMap", out var minuteWordsMap))
            {
                return clockSurface;
            }

            const string path = "surfaces.clock.minuteWordsMap";
            SimpleYamlValue normalizedMinuteWordsMap = minuteWordsMap switch
            {
                SimpleYamlSequence sequence => NormalizeMinuteWordsSequence(localeCode, path, sequence),
                SimpleYamlMapping mapping => NormalizeMinuteWordsMapping(localeCode, path, mapping),
                _ => throw new InvalidOperationException(
                    $"Locale '{localeCode}.{path}' must be a sequence or sparse numeric mapping.")
            };

            var normalizedClockSurface = clockSurface.Values.ToBuilder();
            normalizedClockSurface["minuteWordsMap"] = normalizedMinuteWordsMap;
            return new SimpleYamlMapping(normalizedClockSurface.ToImmutable());
        }

        static SimpleYamlMapping NormalizeMinuteWordsSequence(
            string localeCode,
            string path,
            SimpleYamlSequence sequence)
        {
            if (sequence.Items.Length > 60)
            {
                throw new InvalidOperationException(
                    $"Locale '{localeCode}.{path}' must contain at most 60 entries for minute slots 0 through 59.");
            }

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Use the sequence form for a full 0-59 list, or a mapping keyed by integer minutes for sparse overrides.
  2. For a single override use `minuteWordsMap:` then `15: "a quarter"`.
  3. Rebuild.

Example fix

# before
surfaces:
  clock:
    minuteWordsMap: "quarter"
# after
surfaces:
  clock:
    minuteWordsMap:
      15: "a quarter"
Defensive patterns

Strategy: validation

Validate before calling

import yaml, sys
doc = yaml.safe_load(open(sys.argv[1], encoding='utf-8'))
m = ((doc.get('surfaces') or {}).get('clock') or {}).get('minuteWordsMap')
if m is not None:
    assert isinstance(m, (list, dict)), 'minuteWordsMap must be a sequence or sparse mapping'

Prevention

When it happens

Trigger: Writing `minuteWordsMap: "quarter"` (scalar) or some unsupported node type.

Common situations: Hand-typing a single override as a scalar instead of a one-key mapping.

Related errors


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