Humanizr/Humanizer · error · InvalidOperationException

Phrase '{path}' must define forms, 'symbol', or 'template'.

Error message

Phrase '{path}' must define forms, 'symbol', or 'template'.

What it means

Thrown by the Humanizer source generator while parsing a locale's phrases.dataUnits.<unit> entry in src/Humanizer/Locales/*.yml. A data-unit phrase mapping must provide at least one of 'forms', 'symbol', or 'template'; if all three are absent the generator cannot emit a usable phrase and aborts that locale. The exception is caught in LocaleYamlCatalog and surfaced as compiler diagnostic HSG003 'Invalid locale definition' (severity Error) at build time.

Source

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

        static DataUnitPhrase ParseDataUnitPhrase(SimpleYamlValue value, string path)
        {
            if (value is SimpleYamlScalar scalar)
            {
                return new DataUnitPhrase(PhraseForms.FromScalar(ValidateLiteralText(path, scalar.Value)));
            }

            var mapping = ExpectMapping(value, path);
            RejectUnknownKeys(mapping, path, ["forms", "default", "zero", "singular", "dual", "paucal", "plural", "many", "symbol", "template"]);

            var forms = ParseOptionalPhraseForms(mapping, path);
            var symbol = GetOptionalLiteral(mapping, "symbol", $"{path}.symbol");
            var template = mapping.TryGetValue("template", out var templateValue)
                ? ParseNamedTemplate(templateValue, $"{path}.template", ["count", "unit"])
                : null;
            if (forms is null && symbol is null && template is null)
            {
                throw new InvalidOperationException($"Phrase '{path}' must define forms, 'symbol', or 'template'.");
            }

            return new DataUnitPhrase(forms, symbol, template);
        }

        static TimeUnitPhraseSet ParseTimeUnit(string localeCode, SimpleYamlValue value, string path)
        {
            var mapping = ExpectMapping(value, path);
            var builder = ImmutableDictionary.CreateBuilder<string, TimeUnitPhrase>(StringComparer.Ordinal);

            foreach (var entry in mapping.Values)
            {
                builder[entry.Key] = ParseTimeUnitPhrase(entry.Value, $"{path}.{entry.Key}");
            }

            return new TimeUnitPhraseSet(builder.ToImmutable());
        }

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Open the locale YAML at the path in the message and add at least one of 'forms' (default/singular/plural/...), 'symbol', or 'template' under the offending dataUnits.<unit> entry.
  2. If the unit should be a plain string, replace the mapping with a scalar value (e.g. 'byte: Bytes').
  3. If the entry is unwanted, delete the unit key from dataUnits entirely.
  4. Rebuild; the HSG003 diagnostic for that locale disappears when the phrase is well-formed.

Example fix

# before
dataUnits:
  byte: {}
# after
dataUnits:
  byte:
    forms:
      singular: byte
      plural: bytes
Defensive patterns

Strategy: validation

Validate before calling

# Before authoring, confirm each dataUnits unit has forms, symbol, or template.
# Quick YAML lint (requires yq):
#   yq -o=json '.phrases.dataUnits | to_entries | map(select((.value.forms // .value.symbol // .value.template // .value) == null))' src/Humanizer/Locales/<code>.yml
# Any non-empty output is a unit that will trigger this error.

Prevention

When it happens

Trigger: Authoring phrases.dataUnits.<unit> as a mapping that omits forms, symbol, and template (e.g. an empty block, or a block holding only countPlacement/unknown keys). A null-valued 'symbol:' (unquoted null) also counts as absent because GetOptionalLiteral returns null for it.

Common situations: Copying a sibling unit block and deleting its forms/symbol lines without replacing them; writing 'symbol:' with no value; editing a locale file and leaving a stub unit entry while translating.

Related errors


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