Humanizr/Humanizer · error · InvalidOperationException

Case overlay '{path}.multiple.forms' must explicitly define

Error message

Case overlay '{path}.multiple.forms' must explicitly define reachable '{requiredForm}' form.

What it means

Thrown by ValidateReachableMultipleForms after confirming a 'multiple' key exists, when the locale's plural rule requires a specific named form (e.g. 'dual', 'paucal', 'plural') that is not present in the multiple.forms mapping. The validator iterates the requiredMultipleForms array and throws on the first missing form.

Source

Thrown at src/Humanizer.SourceGenerators/Common/DurationCaseModels.cs:884

            if (multiple.TryGetValue("forms", out var formsValue))
            {
                hasScalarDefault = formsValue is SimpleYamlScalar;
                forms = formsValue as SimpleYamlMapping;
            }
            else
            {
                forms = multiple;
            }

            foreach (var requiredForm in requiredMultipleForms)
            {
                if ((requiredForm == "default" && hasScalarDefault) ||
                    forms?.TryGetValue(requiredForm, out _) == true)
                {
                    continue;
                }

                throw new InvalidOperationException(
                    $"Case overlay '{path}.multiple.forms' must explicitly define reachable '{requiredForm}' form.");
            }
        }

        static void ValidateCitationBaseDurationForms(
            DurationCaseCatalog catalog,
            SimpleYamlValue? phrasesValue,
            ImmutableArray<string> requiredMultipleForms)
        {
            if (!catalog.Realizations.TryGetValue(catalog.CitationCase, out var citation) ||
                citation.Kind != DurationCaseRealizationKind.Authored ||
                citation.Units.Count != 0)
            {
                return;
            }

            var path = $"{catalog.LocaleCode}.phrases.duration";
            var phrases = phrasesValue is null

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Look up the required forms for the locale's plural rule in GetRequiredMultipleForms (e.g. arabic-cardinal needs default, zero, dual, plural, many).
  2. Add the missing named form(s) to the 'multiple.forms' mapping at the reported path.
  3. Ensure 'forms' is a mapping (keyed by form name) and not a scalar string unless only 'default' is required.
  4. Rebuild to confirm all required forms are reachable.

Example fix

# before (slovenian locale; missing 'dual' and 'paucal')
second:
  phrase:
    multiple:
      forms:
        default: sekund
# after
second:
  phrase:
    multiple:
      forms:
        default: sekund
        dual: sekundi
        paucal: sekunde
Defensive patterns

Strategy: validation

Validate before calling

# Map plural rule to required forms and verify each phrase has them
$ruleMap = @{
    'singular-plural' = @('default','plural')
    'arabic-like' = @('default','dual','plural')
    'arabic-cardinal' = @('default','zero','dual','plural','many')
    'polish' = @('default','paucal')
    'slovenian' = @('default','dual','paucal')
}
# For each phrase, check that multiple.forms contains all required form names

Prevention

When it happens

Trigger: The phrase defines a 'multiple.forms' mapping but omits a form that GetRequiredMultipleForms mandates for the locale's plural rule. For example, an 'arabic-like' locale missing 'dual', or a 'slovenian' locale missing 'paucal'.

Common situations: A contributor copies a phrase from a singular-plural locale into an Arabic-like or Slavic locale without adding the extra plural categories. Also occurs when the 'forms' sub-key is a scalar (string) instead of a mapping, leaving all named forms unreachable.

Related errors


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