{"record":{"id":"c76b78d3d4ba7bb6","repo":"Humanizr/Humanizer","slug":"locale-localecode-path-requires-integer-keys","errorCode":null,"errorMessage":"Locale '{localeCode}.{path}' requires integer keys. Invalid key '{entry.Key}'.","messagePattern":"Locale '(.+?)\\.(.+?)' requires integer keys\\. Invalid key '(.+?)'\\.","errorType":"validation","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs","lineNumber":318,"sourceCode":"        }\n\n        static SimpleYamlMapping NormalizeMinuteWordsMapping(\n            string localeCode,\n            string path,\n            SimpleYamlMapping mapping)\n        {\n            if (!mapping.DuplicateKeys.IsDefaultOrEmpty)\n            {\n                throw new InvalidOperationException(\n                    $\"Locale '{localeCode}.{path}' defines duplicate key '{mapping.DuplicateKeys[0]}'.\");\n            }\n\n            var normalizedValues = ImmutableDictionary.CreateBuilder<string, SimpleYamlValue>(StringComparer.Ordinal);\n            foreach (var entry in mapping.Values)\n            {\n                if (!int.TryParse(entry.Key, NumberStyles.Integer, CultureInfo.InvariantCulture, out var minute))\n                {\n                    throw new InvalidOperationException(\n                        $\"Locale '{localeCode}.{path}' requires integer keys. Invalid key '{entry.Key}'.\");\n                }\n\n                if (minute is < 0 or > 59)\n                {\n                    throw new InvalidOperationException(\n                        $\"Locale '{localeCode}.{path}' keys must be between 0 and 59. Invalid key '{entry.Key}'.\");\n                }\n\n                var canonicalKey = minute.ToString(CultureInfo.InvariantCulture);\n                if (normalizedValues.ContainsKey(canonicalKey))\n                {\n                    throw new InvalidOperationException(\n                        $\"Locale '{localeCode}.{path}' defines duplicate numeric minute slot {minute}.\");\n                }\n\n                ValidateMinuteWordValue(localeCode, path, entry.Key, entry.Value, allowEmpty: false);\n                normalizedValues[canonicalKey] = entry.Value;","sourceCodeStart":300,"sourceCodeEnd":336,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs#L300-L336","documentation":"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.","triggerScenarios":"A key like `quarter:` or `15a:` in the sparse mapping; a quoted-but-non-numeric key.","commonSituations":"Mixing dense-style word labels as keys; copy-paste errors.","solutions":["Replace non-integer keys with integer minute values 0-59.","If you meant a label, it belongs as the value, not the key.","Rebuild."],"exampleFix":"# before\nsurfaces:\n  clock:\n    minuteWordsMap:\n      quarter: \"15\"\n# after\nsurfaces:\n  clock:\n    minuteWordsMap:\n      15: \"a quarter\"","handlingStrategy":"validation","validationCode":"import yaml, sys\ndoc = yaml.safe_load(open(sys.argv[1], encoding='utf-8'))\nm = ((doc.get('surfaces') or {}).get('clock') or {}).get('minuteWordsMap')\nif isinstance(m, dict):\n    for k in m:\n        assert str(k).isdigit(), f'minuteWordsMap key {k!r} is not an integer'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Author locales against the canonical schema; the error message lists the exact allowed names.","Run `dotnet build src/Humanizer/Humanizer.csproj` locally so the generator reports locale errors before push.","Copy an existing compliant locale file as your template rather than writing YAML from scratch."],"tags":["locale-authoring","yaml","source-generator","build","localization","clock"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}