{"record":{"id":"342380169448b8b8","repo":"Humanizr/Humanizer","slug":"duplicate-inflection-rule-id-id","errorCode":null,"errorMessage":"Duplicate inflection rule id '{id}'.","messagePattern":"Duplicate inflection rule id '(.+?)'\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Humanizer.SourceGenerators/Generators/ProfileCatalogs/InflectionCatalogParsing.cs","lineNumber":434,"sourceCode":"\n            var rules = ImmutableArray.CreateBuilder<InflectionRuleInput>();\n            var ids = new HashSet<string>(StringComparer.Ordinal);\n            foreach (var item in sequence.Items)\n            {\n                if (item is not SimpleYamlMapping rule)\n                {\n                    throw new InvalidOperationException(\"Inflection rules must be mappings.\");\n                }\n\n                ValidateProperties(\n                    rule,\n                    \"Inflection rule\",\n                    \"id\", \"direction\", \"priority\", \"scope\", \"match\", \"output\",\n                    \"hostileExclusions\", \"hostile-exclusions\", \"reverse\", \"sources\");\n                var id = GetRequiredScalar(rule, \"id\", \"Inflection rule must define id\");\n                if (!ids.Add(id))\n                {\n                    throw new InvalidOperationException($\"Duplicate inflection rule id '{id}'.\");\n                }\n\n                ValidateSources(rule, sourceIds, $\"Inflection rule '{id}'\");\n                var direction = GetRequiredScalar(rule, \"direction\", $\"Inflection rule '{id}' must define direction\");\n                if (direction is not (\"forward\" or \"reverse\"))\n                {\n                    throw new InvalidOperationException($\"Inflection rule '{id}' has unsupported direction '{direction}'.\");\n                }\n\n                var priority = GetRequiredInt(rule, \"priority\", $\"Inflection rule '{id}' must define priority\");\n                var scope = GetRequiredMapping(rule, \"scope\", $\"Inflection rule '{id}' must define scope\");\n                ValidateProperties(\n                    scope,\n                    $\"Inflection rule '{id}' scope\",\n                    \"pos\", \"countability\", \"token\", \"scripts\");\n                if (GetRequiredScalar(scope, \"pos\", $\"Inflection rule '{id}' scope must define pos\") != \"noun\" ||\n                    GetRequiredScalar(scope, \"token\", $\"Inflection rule '{id}' scope must define token\") != \"standalone\")\n                {","sourceCodeStart":416,"sourceCodeEnd":452,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer.SourceGenerators/Generators/ProfileCatalogs/InflectionCatalogParsing.cs#L416-L452","documentation":"Rule ids must be unique within a locale (ordinal comparison). ParseRules tracks ids in a HashSet and throws when a second entry reuses an id.","triggerScenarios":"Two 'rules:' entries share the same 'id:' value.","commonSituations":"Copy-pasting a rule block to create a variant without renaming the id.","solutions":["Give each rule a unique id (e.g. encode direction and suffix in the id, like 'zz.forward.consonant-y')"],"exampleFix":"# before\n      - id: 'zz.forward.consonant-y'\n        ...\n      - id: 'zz.forward.consonant-y'\n# after\n      - id: 'zz.forward.consonant-y'\n        ...\n      - id: 'zz.forward.vowel-y'\n","handlingStrategy":"validation","validationCode":"var ids = new HashSet<string>(StringComparer.Ordinal);\nforeach (var rule in rules)\n    if (!ids.Add(rule.Id))\n        Report($\"{locale}: duplicate rule id '{rule.Id}'.\");","typeGuard":"static bool RuleIdsUnique(IEnumerable<Rule> rules) =>\n    rules.Select(r => r.Id).Distinct(StringComparer.Ordinal).Count() == rules.Count();","tryCatchPattern":null,"preventionTips":["Encode direction and suffix in the id (e.g. en.forward.consonant-y)"],"tags":["inflection","localization","yaml","source-generator","locale","validation"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}