Humanizr/Humanizer · error · InvalidOperationException
Invariant bundle cannot define productive rules.
Error message
Invariant bundle cannot define productive rules.
What it means
An inflection owner with capability 'invariant' must not define any productive inflection rules. Invariant bundles represent nouns whose forms do not change across number/case, so rule-driven transformation is contradictory. The validator rejects any non-empty rules array on an invariant owner.
Source
Thrown at src/Humanizer.SourceGenerators/Generators/ProfileCatalogs/InflectionCatalogValidation.cs:164
throw new InvalidOperationException(
$"Inflection rule '{ruleId}' output must contain exactly one bounded '{{stem}}' placeholder.");
}
}
static void ValidateInvariantCapability(
string capability,
string casing,
ImmutableArray<InflectionLexemeInput> lexemes,
ImmutableArray<InflectionRuleInput> rules)
{
if (capability != "invariant")
{
return;
}
if (!rules.IsEmpty)
{
throw new InvalidOperationException(
"Invariant bundle cannot define productive rules.");
}
foreach (var lexeme in lexemes)
{
var forms = lexeme.Singular.Accepted
.Concat(lexeme.DictionaryPlural.Accepted)
.Concat(lexeme.Display.Values.SelectMany(static form => form.Accepted))
.Distinct(casing == "lower-title-upper"
? global::Humanizer.InflectionUnicodeData.SimpleCaseComparer.Instance
: StringComparer.Ordinal);
if (forms.Skip(1).Any())
{
throw new InvalidOperationException(
$"Invariant inflection lexeme '{lexeme.Id}' has divergent reachable forms.");
}
}
}View on GitHub (pinned to ffc2b77c0f)
Solutions
- Remove all entries from the 'rules:' list (or remove the key entirely) for the invariant owner.
- If the noun genuinely needs inflection, change 'capability' from 'invariant' to the appropriate productive value.
- Review whether the owner should be split: invariant nouns in one owner, productive nouns in another.
Example fix
# before
owners:
- capability: 'invariant'
rules:
- id: 'plural-es'
output: '{stem}s'
# after
owners:
- capability: 'invariant'
rules: [] Defensive patterns
Strategy: validation
Validate before calling
# Before building, verify invariant owners have no rules.
python3 -c "
import yaml, sys
for f in sys.argv[1:]:
d = yaml.safe_load(open(f))
owners = (d.get('inflection',{}).get('owners') or [])
for owner in owners:
if owner.get('capability') == 'invariant' and (owner.get('rules') or []):
print(f'{f}: invariant owner defines rules — remove them')
" src/Humanizer/Locales/*.yml Prevention
- When setting capability to 'invariant', immediately delete or empty the rules array.
- Use a YAML template that has rules: [] commented out for invariant owners.
- Understand that invariant means zero productive transformation — if rules are needed, the noun is not invariant.
When it happens
Trigger: An inflection owner YAML block has 'capability: invariant' and simultaneously has a non-empty 'rules:' list. The check at line 162 fires because rules.IsEmpty is false.
Common situations: Changing a locale's capability to 'invariant' without removing its previously productive rules. Copying a productive locale as a template for an invariant one and forgetting to strip the rules section.
Related errors
- Inflection rule '{ruleId}' output must contain exactly one b
- Invariant inflection lexeme '{lexeme.Id}' has divergent reac
- Productive evidence '{direction}' requires at least 100 atte
- {subject} references unknown source '{source}'.
- Inflection source '{entry.Key}' must define non-empty kind a
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/694f0b3881c72786.
Report an issue: GitHub.