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
- 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.
- If the unit should be a plain string, replace the mapping with a scalar value (e.g. 'byte: Bytes').
- If the entry is unwanted, delete the unit key from dataUnits entirely.
- 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 stubbing a new data unit, write the forms/symbol block in the same edit rather than leaving an empty mapping.
- Keep a sibling fully-authored unit beside the cursor as the copy source.
- Run the build after each locale edit so HSG003 points at the exact path.
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
- Phrase '{path}' must define forms.
- Phrase '{path}' must define 'numeric', 'text', or 'words'.
- Phrase forms '{path}' must define at least one form.
- Phrase '{path}.countPlacement' uses unsupported count placem
- Template '{path}' must define a scalar 'value'.
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/d8defc8ea02389bb.
Report an issue: GitHub.