Humanizr/Humanizer · error · InvalidOperationException

Case overlay '{path}' must explicitly define singular and nu

Error message

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

What it means

After sameAsNominative/unsupported checks, ParseUnit (DurationCaseModels.cs:1178-1184) parses the unit as a TimeSpan phrase via LocalePhraseNormalization.ParseTimeSpanPhrase and requires both phrase.Single and phrase.Multiple?.Forms to be non-null. A phrase unit missing its singular form or its numeric multiple forms is rejected so generated code always has both.

Source

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

                return new DurationCaseUnit(DurationCaseUnitKind.SameAsNominative, null);
            }

            if (mapping.GetScalar("unsupported") is { } unsupported)
            {
                RejectUnknownKeys(mapping, path, ["unsupported"]);
                if (!bool.TryParse(unsupported, out var enabled) || !enabled)
                {
                    throw new InvalidOperationException($"'{path}.unsupported' must be true.");
                }

                return new DurationCaseUnit(DurationCaseUnitKind.Unsupported, null);
            }

            var phrase = LocalePhraseNormalization.ParseTimeSpanPhrase(value, path);
            if (phrase.Single is null ||
                phrase.Multiple?.Forms is null)
            {
                throw new InvalidOperationException(
                    $"Case overlay '{path}' must explicitly define singular and numeric multiple forms.");
            }

            return new DurationCaseUnit(DurationCaseUnitKind.Phrase, phrase);
        }

        static bool ContainsInheritanceMarker(SimpleYamlValue value) =>
            value switch
            {
                SimpleYamlScalar scalar => scalar.Value.Contains("↑↑↑", StringComparison.Ordinal),
                SimpleYamlMapping mapping => mapping.Values.Values.Any(ContainsInheritanceMarker),
                SimpleYamlSequence sequence => sequence.Items.Any(ContainsInheritanceMarker),
                _ => false
            };

        static SimpleYamlMapping ExpectMapping(SimpleYamlValue value, string path) =>
            value as SimpleYamlMapping
            ?? throw new InvalidOperationException($"'{path}' must be a mapping.");

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Add the missing half: ensure phrase.single (with numeric/words) AND phrase.multiple.forms (default/singular/etc.) both exist.
  2. If only the singular exists and no plural is needed, still provide a multiple.forms entry (often mirroring the singular).
  3. If the unit should not have a phrase, switch it to sameAsNominative: true or unsupported: true.

Example fix

# before - multiple missing forms
second:
  phrase:
    single: { numeric: '1 sekunda', words: 'jedna sekunda' }
    multiple: {}
# after
second:
  phrase:
    single: { numeric: '1 sekunda', words: 'jedna sekunda' }
    multiple:
      forms: { default: 'sekund', singular: 'sekundy', plural: 'sekund' }
Defensive patterns

Strategy: validation

Validate before calling

# A phrase unit must define single and multiple.forms
foreach ($u in $caseUnits.GetEnumerator()) {
    $v = $u.Value
    if ($v -is [hashtable] -and $v.ContainsKey('phrase')) {
        $p = $v.phrase
        if (-not $p.single -or -not $p.multiple -or -not $p.multiple.forms) {
            throw "unit '$($u.Key)' phrase must define single and multiple.forms"
        }
    }
}

Prevention

When it happens

Trigger: A unit's phrase: block has single: but no multiple: (or multiple: without forms:), or vice-versa.

Common situations: Incomplete phrase authoring; copying a phrase block from a locale whose multiple-form shape differs; forgetting the forms: level under multiple:.

Related errors


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