Humanizr/Humanizer · error · InvalidOperationException

Locale '{localeCode}.surfaces.clock.minuteWordsMap' defines

Error message

Locale '{localeCode}.surfaces.clock.minuteWordsMap' defines duplicate entries; choose either the dense or sparse form.

What it means

`surfaces.clock.minuteWordsMap` can appear in either a dense (sequence) or sparse (numeric-keyed mapping) form, but not both — and the key must not be duplicated (CanonicalLocaleAuthoring.cs:256-260). Duplicate keys usually mean both forms were pasted in.

Source

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

            if (numberSurface.TryGetValue("formatting", out var fmtValue))
            {
                if (fmtValue is not SimpleYamlMapping fmtMapping)
                {
                    throw new InvalidOperationException(
                        $"Locale '{localeCode}.surfaces.number.formatting' must be a mapping, not a scalar or sequence.");
                }

                ValidateNumberFormattingBlock(localeCode, fmtMapping);
                features["numberFormatting"] = fmtMapping;
            }
        }

        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();

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Keep exactly one minuteWordsMap entry: either the sequence or the sparse mapping.
  2. If you want a few overrides, prefer the sparse form with integer keys 0-59.
  3. Rebuild.

Example fix

# before
surfaces:
  clock:
    minuteWordsMap: [zero, five, ten]
    minuteWordsMap:
      15: "a quarter"
# after
surfaces:
  clock:
    minuteWordsMap:
      15: "a quarter"
Defensive patterns

Strategy: validation

Validate before calling

import yaml, sys
# PyYAML collapses duplicate keys; use the generator's SimpleYamlParser or grep:
text = open(sys.argv[1], encoding='utf-8').read()
assert text.count('minuteWordsMap:') <= 1, 'minuteWordsMap declared more than once'

Prevention

When it happens

Trigger: The minuteWordsMap key appears twice in the clock surface (DuplicateKeys includes it), e.g. one sequence form and one mapping form.

Common situations: Merging two locale branches that each added minuteWordsMap; hand-editing and leaving the old form.

Related errors


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