Humanizr/Humanizer · error · InvalidOperationException

Inflection {subject} contains text outside its declared scri

Error message

Inflection {subject} contains text outside its declared scripts.

What it means

After NFC normalization and optional casing, authored text is checked against the inflection owner's declared Unicode scripts. Every letter and mark must belong to one of the scripts declared in the owner's 'scripts:' list. Characters outside the declared scripts (or non-letter characters when allowNonLetters is false) cause rejection.

Source

Thrown at src/Humanizer.SourceGenerators/Generators/ProfileCatalogs/InflectionCatalogValidation.cs:253

            if (casing == "lower-title-upper")
            {
                if (!TryNormalizeSimpleLower(normalized, out var lower))
                {
                    throw new InvalidOperationException(
                        $"Inflection {subject} has an unsupported casing expansion.");
                }

                normalized = lower;
            }

            var literal = allowStemPlaceholder
                ? normalized.Replace("{stem}", string.Empty)
                : normalized;
            if (literal.Length > 0 &&
                !HasOnlyDeclaredScripts(literal, ownerScripts, allowNonLetters))
            {
                throw new InvalidOperationException(
                    $"Inflection {subject} contains text outside its declared scripts.");
            }

            return normalized;
        }

        static bool TryNormalizeSimpleLower(string value, out string normalized)
        {
            var builder = new StringBuilder(value.Length);
            for (var index = 0; index < value.Length;)
            {
                var scalarOffset = index;
                var first = value[index++];
                int scalar;
                if (char.IsHighSurrogate(first))
                {
                    if (index >= value.Length || !char.IsLowSurrogate(value[index]))
                    {

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Add the missing Unicode script name to the owner's 'scripts:' list (e.g., add 'latin' alongside 'cyrillic').
  2. Remove characters from the authored text that belong to undeclared scripts or are non-letters when not allowed.
  3. If the field supports non-letters, verify allowStemPlaceholder/allowNonLetters is configured correctly for that call path.

Example fix

# before
owners:
  - scripts: ['cyrillic']
lexemes:
  - singular:
      accepted: ['PDF документ']
# after
owners:
  - scripts: ['cyrillic', 'latin']
lexemes:
  - singular:
      accepted: ['PDF документ']
Defensive patterns

Strategy: validation

Validate before calling

# Before building, verify all letter characters belong to declared scripts.
python3 -c "
import yaml, sys, unicodedata
for f in sys.argv[1:]:
    d = yaml.safe_load(open(f))
    owners = (d.get('inflection',{}).get('owners') or [])
    for owner in owners:
        declared = set(owner.get('scripts') or [])
        for lex in (owner.get('lexemes') or []):
            for v in ((lex.get('singular') or {}).get('accepted') or []):
                for ch in v:
                    if ch.isalpha():
                        script = unicodedata.name(ch,'').split()[0].lower()
                        if script not in declared:
                            print(f'{f}: char {ch!r} script {script!r} not in declared {declared}')
" src/Humanizer/Locales/*.yml

Prevention

When it happens

Trigger: A lexeme or guard text contains characters from a Unicode script not listed in the owner's 'scripts:' array, or contains non-letter characters (digits, punctuation) when allowNonLetters is false. The HasOnlyDeclaredScripts method returns false for the literal.

Common situations: Mixing Latin loanwords into a Cyrillic-script locale without declaring 'latin' in scripts. Using digits or hyphens in form text when the field does not allow non-letters. Adding a new script to forms but forgetting to update the owner's scripts list.

Related errors


AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13). Data as JSON: /api/errors/809346c4c4ab8ecb. Report an issue: GitHub.