Humanizr/Humanizer · error · InvalidOperationException

Locale ' . ' defines duplicate key ' '.

Error message

Locale '{localeCode}.{path}' defines duplicate key '{mapping.DuplicateKeys[0]}'.

What it means

In the sparse (mapping) form of minuteWordsMap, the same numeric key must not appear more than once (CanonicalLocaleAuthoring.cs:307-311). The parser records duplicate keys and the generator reports the first.

Solutions

  1. Delete the duplicate so each minute key appears once.
  2. Use canonical integer keys (no leading zeros, no quotes) to avoid string/number aliasing.
  3. Rebuild.

Example fix

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

Strategy: validation

Validate before calling

# SimpleYamlParser preserves duplicate keys; grep for repeats:
import re, sys
text = open(sys.argv[1], encoding='utf-8').read()
keys = re.findall(r'(?m)^\s*(\d+):', text)
seen = set()
for k in keys:
    assert k not in seen, f'duplicate minute key {k}'
    seen.add(k)

Prevention

When it happens

Trigger: Two `15:` entries, or a numeric-vs-string duplicate ("15" and 15) collapsed by the YAML parser into a duplicate.

Common situations: Merge conflicts resolved by keeping both; copy-paste of an override block.

Related errors


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

Appendix: source

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

            var normalizedValues = ImmutableDictionary.CreateBuilder<string, SimpleYamlValue>(StringComparer.Ordinal);
            for (var index = 0; index < sequence.Items.Length; index++)
            {
                ValidateMinuteWordValue(localeCode, path, index.ToString(CultureInfo.InvariantCulture), sequence.Items[index], allowEmpty: true);
                normalizedValues[index.ToString(CultureInfo.InvariantCulture)] = sequence.Items[index];
            }

            return new SimpleYamlMapping(normalizedValues.ToImmutable());
        }

        static SimpleYamlMapping NormalizeMinuteWordsMapping(
            string localeCode,
            string path,
            SimpleYamlMapping mapping)
        {
            if (!mapping.DuplicateKeys.IsDefaultOrEmpty)
            {
                throw new InvalidOperationException(
                    $"Locale '{localeCode}.{path}' defines duplicate key '{mapping.DuplicateKeys[0]}'.");
            }

            var normalizedValues = ImmutableDictionary.CreateBuilder<string, SimpleYamlValue>(StringComparer.Ordinal);
            foreach (var entry in mapping.Values)
            {
                if (!int.TryParse(entry.Key, NumberStyles.Integer, CultureInfo.InvariantCulture, out var minute))
                {
                    throw new InvalidOperationException(
                        $"Locale '{localeCode}.{path}' requires integer keys. Invalid key '{entry.Key}'.");
                }

                if (minute is < 0 or > 59)
                {
                    throw new InvalidOperationException(
                        $"Locale '{localeCode}.{path}' keys must be between 0 and 59. Invalid key '{entry.Key}'.");
                }

View on GitHub (pinned to ffc2b77c0f)