{"record":{"id":"e9f24dc805b21da2","repo":"Humanizr/Humanizer","slug":"locale-localecode-path-defines-duplicate-key","errorCode":null,"errorMessage":"Locale '{localeCode}.{path}' defines duplicate key '{mapping.DuplicateKeys[0]}'.","messagePattern":"Locale '(.+?)\\.(.+?)' defines duplicate key '(.+?)'\\.","errorType":"validation","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs","lineNumber":309,"sourceCode":"\n            var normalizedValues = ImmutableDictionary.CreateBuilder<string, SimpleYamlValue>(StringComparer.Ordinal);\n            for (var index = 0; index < sequence.Items.Length; index++)\n            {\n                ValidateMinuteWordValue(localeCode, path, index.ToString(CultureInfo.InvariantCulture), sequence.Items[index], allowEmpty: true);\n                normalizedValues[index.ToString(CultureInfo.InvariantCulture)] = sequence.Items[index];\n            }\n\n            return new SimpleYamlMapping(normalizedValues.ToImmutable());\n        }\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","sourceCodeStart":291,"sourceCodeEnd":327,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs#L291-L327","documentation":"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.","triggerScenarios":"Two `15:` entries, or a numeric-vs-string duplicate (\"15\" and 15) collapsed by the YAML parser into a duplicate.","commonSituations":"Merge conflicts resolved by keeping both; copy-paste of an override block.","solutions":["Delete the duplicate so each minute key appears once.","Use canonical integer keys (no leading zeros, no quotes) to avoid string/number aliasing.","Rebuild."],"exampleFix":"# before\nsurfaces:\n  clock:\n    minuteWordsMap:\n      15: \"a quarter\"\n      15: \"quarter past\"\n# after\nsurfaces:\n  clock:\n    minuteWordsMap:\n      15: \"a quarter\"","handlingStrategy":"validation","validationCode":"# SimpleYamlParser preserves duplicate keys; grep for repeats:\nimport re, sys\ntext = open(sys.argv[1], encoding='utf-8').read()\nkeys = re.findall(r'(?m)^\\s*(\\d+):', text)\nseen = set()\nfor k in keys:\n    assert k not in seen, f'duplicate minute key {k}'\n    seen.add(k)","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"}