Humanizr/Humanizer · error · InvalidOperationException

Phrase forms '{path}' must define at least one form.

Error message

Phrase forms '{path}' must define at least one form.

What it means

Thrown by ParsePhraseForms when a 'forms' mapping contains none of the recognized form keys (default, zero, singular, dual, paucal, plural, many). At least one form is required so the phrase has a fallback rendering. Surfaced as compiler diagnostic HSG003 (severity Error).

Source

Thrown at src/Humanizer.SourceGenerators/Common/LocalePhraseNormalization.cs:384

        }

        static PhraseForms ParsePhraseForms(
            SimpleYamlValue value,
            string path,
            bool preserveDuplicateForms,
            params string[] allowedPlaceholders)
        {
            if (value is SimpleYamlScalar scalar)
            {
                var scalarForms = PhraseForms.FromScalar(ValidateLiteralText(path, scalar.Value, allowedPlaceholders));
                return preserveDuplicateForms ? scalarForms : scalarForms.CollapseDuplicates();
            }

            var mapping = ExpectMapping(value, path);
            RejectUnknownKeys(mapping, path, ["default", "zero", "singular", "dual", "paucal", "plural", "many"]);
            if (!TryParseDirectPhraseForms(mapping, path, out var forms, allowedPlaceholders))
            {
                throw new InvalidOperationException($"Phrase forms '{path}' must define at least one form.");
            }

            return preserveDuplicateForms ? forms : forms.CollapseDuplicates();
        }

        static bool TryParseDirectPhraseForms(SimpleYamlMapping mapping, string path, out PhraseForms forms, params string[] allowedPlaceholders)
        {
            var defaultValue = GetOptionalLiteral(mapping, "default", $"{path}.default", allowedPlaceholders);
            var zero = GetOptionalLiteral(mapping, "zero", $"{path}.zero", allowedPlaceholders);
            var singular = GetOptionalLiteral(mapping, "singular", $"{path}.singular", allowedPlaceholders);
            var dual = GetOptionalLiteral(mapping, "dual", $"{path}.dual", allowedPlaceholders);
            var paucal = GetOptionalLiteral(mapping, "paucal", $"{path}.paucal", allowedPlaceholders);
            var plural = GetOptionalLiteral(mapping, "plural", $"{path}.plural", allowedPlaceholders);
            var many = GetOptionalLiteral(mapping, "many", $"{path}.many", allowedPlaceholders);

            defaultValue ??= zero ?? singular ?? dual ?? paucal ?? plural ?? many;
            if (defaultValue is null)
            {

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Add at least one recognized form key (default, zero, singular, dual, paucal, plural, many) to the forms mapping.
  2. Ensure 'default' is set so all uncovered counts fall back to it.
  3. Rebuild to confirm the HSG003 diagnostic clears.

Example fix

# before
forms: {}
# after
forms:
  default: hours
  singular: hour
  plural: hours
Defensive patterns

Strategy: validation

Validate before calling

# A forms mapping must contain at least one of the known form keys.
known=[default zero singular dual paucal plural many]
yq -o=json '.phrases | .. | select(has("forms")) | .forms | select(tag == "!!map") | select([keys[] | select(. as $k | $known | index($k))] | length == 0)' src/Humanizer/Locales/<code>.yml

Prevention

When it happens

Trigger: Authoring a forms: {} empty mapping, or a forms mapping that uses only unrecognized keys (typos like 'one'/'many2' instead of singular/plural).

Common situations: Translating only some forms and accidentally deleting the default/singular key; mistyping a form key; leaving forms: as a placeholder.

Related errors


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