{"record":{"id":"8c4960a0ff53edae","repo":"Humanizr/Humanizer","slug":"locale-localecode-path-defines-duplicate-num","errorCode":null,"errorMessage":"Locale '{localeCode}.{path}' defines duplicate numeric minute slot {minute}.","messagePattern":"Locale '(.+?)\\.(.+?)' defines duplicate numeric minute slot (.+?)\\.","errorType":"validation","errorClass":"InvalidOperationException","httpStatus":null,"severity":"critical","filePath":"src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs","lineNumber":331,"sourceCode":"            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;\n            }\n\n            return new SimpleYamlMapping(normalizedValues.ToImmutable());\n        }\n\n        static void ValidateMinuteWordValue(\n            string localeCode,\n            string path,\n            string key,\n            SimpleYamlValue value,\n            bool allowEmpty)\n        {\n            if (value is not SimpleYamlScalar scalar || !scalar.IsString)","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs#L313-L349","documentation":"Thrown by the Humanizer source generator while normalizing the clock 'minutes' mapping of a locale YAML file. After keys are parsed to integers and canonicalized, two distinct string keys (e.g. '1' and '01') collapse to the same numeric minute slot, which the schema forbids. It fails the build so locale data cannot silently lose one of the two entries.","triggerScenarios":"A locale YAML under src/Humanizer/Loccales defines surfaces.clock.minutes with two keys that parse to the same integer (e.g. '01: one' and '1: one', or '1' plus '1.0'). NormalizeMinuteWordsMapping builds an ordinal dictionary keyed by minute.ToString() and detects the collision at line 329-332.","commonSituations":"A contributor copies minute entries from another locale and forgets to delete the original; zero-padding keys inconsistently ('5' vs '05'); merging two locales whose minute tables overlap. Fires during 'dotnet build'/'dotnet pack' of the Humanizer project, not at consumer runtime.","solutions":["Open the locale YAML cited by {path} (e.g. surfaces.clock.minutes) and remove or rename one of the two entries that share the same integer value.","Re-key all minute slots as plain integers with no zero-padding so collisions are visually obvious, then rebuild.","Search the file for the integer form of {minute} to find both spelling variants and keep only one."],"exampleFix":"// before (surfaces.clock.minutes)\nminutes:\n  01: one minute\n  1: a minute\n// after\nminutes:\n  1: one minute","handlingStrategy":"validation","validationCode":"# Before editing a clock minutes mapping, confirm each integer slot appears once.\n# PowerShell check against the parsed YAML keys:\n$keys = @('1','01','2','02')\n$dups = $keys | ForEach-Object { [int]::Parse($_) } | Group-Object | Where-Object { $_.Count -gt 1 }\nif ($dups) { Write-Error \"Duplicate minute slot: $($dups.Name)\" }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always key clock minute entries as bare integers (no zero-padding) so collisions are visually obvious.","Run 'dotnet build src/Humanizer/Humanizer.csproj' after every locale edit; the source generator reports the offending {path} and {minute}.","When merging two locale files, deduplicate minute slots by integer value, not by raw string key."],"tags":["localization","yaml","source-generator","locale","build"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}