Humanizr/Humanizer · error · InvalidOperationException
Duplicate inflection rule id '{id}'.
Error message
Duplicate inflection rule id '{id}'. What it means
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.
Source
Thrown at src/Humanizer.SourceGenerators/Generators/ProfileCatalogs/InflectionCatalogParsing.cs:434
var rules = ImmutableArray.CreateBuilder<InflectionRuleInput>();
var ids = new HashSet<string>(StringComparer.Ordinal);
foreach (var item in sequence.Items)
{
if (item is not SimpleYamlMapping rule)
{
throw new InvalidOperationException("Inflection rules must be mappings.");
}
ValidateProperties(
rule,
"Inflection rule",
"id", "direction", "priority", "scope", "match", "output",
"hostileExclusions", "hostile-exclusions", "reverse", "sources");
var id = GetRequiredScalar(rule, "id", "Inflection rule must define id");
if (!ids.Add(id))
{
throw new InvalidOperationException($"Duplicate inflection rule id '{id}'.");
}
ValidateSources(rule, sourceIds, $"Inflection rule '{id}'");
var direction = GetRequiredScalar(rule, "direction", $"Inflection rule '{id}' must define direction");
if (direction is not ("forward" or "reverse"))
{
throw new InvalidOperationException($"Inflection rule '{id}' has unsupported direction '{direction}'.");
}
var priority = GetRequiredInt(rule, "priority", $"Inflection rule '{id}' must define priority");
var scope = GetRequiredMapping(rule, "scope", $"Inflection rule '{id}' must define scope");
ValidateProperties(
scope,
$"Inflection rule '{id}' scope",
"pos", "countability", "token", "scripts");
if (GetRequiredScalar(scope, "pos", $"Inflection rule '{id}' scope must define pos") != "noun" ||
GetRequiredScalar(scope, "token", $"Inflection rule '{id}' scope must define token") != "standalone")
{View on GitHub (pinned to ffc2b77c0f)
Solutions
- Give each rule a unique id (e.g. encode direction and suffix in the id, like 'zz.forward.consonant-y')
Example fix
# before
- id: 'zz.forward.consonant-y'
...
- id: 'zz.forward.consonant-y'
# after
- id: 'zz.forward.consonant-y'
...
- id: 'zz.forward.vowel-y'
Defensive patterns
Strategy: validation
Validate before calling
var ids = new HashSet<string>(StringComparer.Ordinal);
foreach (var rule in rules)
if (!ids.Add(rule.Id))
Report($"{locale}: duplicate rule id '{rule.Id}'."); Type guard
static bool RuleIdsUnique(IEnumerable<Rule> rules) =>
rules.Select(r => r.Id).Distinct(StringComparer.Ordinal).Count() == rules.Count(); Prevention
- Encode direction and suffix in the id (e.g. en.forward.consonant-y)
When it happens
Trigger: Two 'rules:' entries share the same 'id:' value.
Common situations: Copy-pasting a rule block to create a variant without renaming the id.
Related errors
- Inflection defines unsupported quantity selector; expected '
- Inflection quantitySelector 'exact-numeric-singleton' requir
- Inflection quantitySelector 'exact-numeric-singleton' cannot
- Inflection display category 'one' is unreachable without qua
- Active inflection bundle must define lexemes.
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/342380169448b8b8.
Report an issue: GitHub.