Humanizr/Humanizer · error · InvalidOperationException

Locale '{localeCode}.{path}' requires integer keys. Invalid

Error message

Locale '{localeCode}.{path}' requires integer keys. Invalid key '{entry.Key}'.

What it means

Each key in the sparse minuteWordsMap form must parse as an integer (CanonicalLocaleAuthoring.cs:316-320, invariant culture). Minute slots are numeric, so labels like 'quarter' are not valid keys.

Source

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

        }

        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}'.");
                }

                var canonicalKey = minute.ToString(CultureInfo.InvariantCulture);
                if (normalizedValues.ContainsKey(canonicalKey))
                {
                    throw new InvalidOperationException(
                        $"Locale '{localeCode}.{path}' defines duplicate numeric minute slot {minute}.");
                }

                ValidateMinuteWordValue(localeCode, path, entry.Key, entry.Value, allowEmpty: false);
                normalizedValues[canonicalKey] = entry.Value;

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Replace non-integer keys with integer minute values 0-59.
  2. If you meant a label, it belongs as the value, not the key.
  3. Rebuild.

Example fix

# before
surfaces:
  clock:
    minuteWordsMap:
      quarter: "15"
# 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 isinstance(m, dict):
    for k in m:
        assert str(k).isdigit(), f'minuteWordsMap key {k!r} is not an integer'

Prevention

When it happens

Trigger: A key like `quarter:` or `15a:` in the sparse mapping; a quoted-but-non-numeric key.

Common situations: Mixing dense-style word labels as keys; copy-paste errors.

Related errors


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