Humanizr/Humanizer · error · InvalidOperationException
Phrase '{path}' must define 'numeric', 'text', or 'words'.
Error message
Phrase '{path}' must define 'numeric', 'text', or 'words'. What it means
Thrown by ParseSinglePhraseWithWordsVariant when a duration phrase's 'single' entry is a mapping but defines none of 'numeric', 'text', or 'words'. The single form must carry at least one of these so the generator can render the count-1 case. Surfaced as compiler diagnostic HSG003 (severity Error).
Source
Thrown at src/Humanizer.SourceGenerators/Common/LocalePhraseNormalization.cs:333
namedTemplate);
}
static (string? Single, string? WordsVariant) ParseSinglePhraseWithWordsVariant(SimpleYamlValue value, string path)
{
if (value is SimpleYamlScalar scalar)
{
return (ValidateLiteralText(path, scalar.Value), null);
}
var mapping = ExpectMapping(value, path);
RejectUnknownKeys(mapping, path, ["numeric", "text", "words"]);
var single = GetOptionalLiteral(mapping, "numeric", $"{path}.numeric") ??
GetOptionalLiteral(mapping, "text", $"{path}.text");
var wordsVariant = GetOptionalLiteral(mapping, "words", $"{path}.words");
if (single is null && wordsVariant is null)
{
throw new InvalidOperationException($"Phrase '{path}' must define 'numeric', 'text', or 'words'.");
}
return (single, wordsVariant);
}
static PhraseForms? ParseOptionalPhraseForms(
SimpleYamlMapping mapping,
string path,
params string[] allowedPlaceholders) =>
ParseOptionalPhraseForms(mapping, path, preserveDuplicateForms: false, allowedPlaceholders);
static PhraseForms? ParseOptionalPhraseForms(
SimpleYamlMapping mapping,
string path,
bool preserveDuplicateForms,
params string[] allowedPlaceholders)
{
if (mapping.TryGetValue("forms", out var formsValue))View on GitHub (pinned to ffc2b77c0f)
Solutions
- Provide 'numeric' (digit form, e.g. '1 hour'), 'text' (spelled-out form), and/or 'words' (words-only variant) under the single mapping.
- If no distinction is needed, replace the mapping with a scalar string for single.
- Remove the single key to inherit or omit it as the locale design allows.
- Rebuild to confirm the diagnostic clears.
Example fix
# before
duration:
hour:
single: {}
# after
duration:
hour:
single:
numeric: 1 hour
words: one hour Defensive patterns
Strategy: validation
Validate before calling
# A 'single' mapping under a duration unit must define numeric/text/words. # yq -o=json '.phrases.duration | to_entries[] | select(.value.single | tag == "!!map") | select((.value.single.numeric // .value.single.text // .value.single.words) == null) | .key' src/Humanizer/Locales/<code>.yml
Prevention
- If 'single' needs no variants, make it a scalar rather than a mapping.
- When using a mapping, fill numeric (or text) immediately.
- Build after each edit to catch the empty mapping early.
When it happens
Trigger: Authoring phrases.duration.<unit>.single as a mapping with only unknown keys, or with all three of numeric/text/words set to unquoted null.
Common situations: Author writes a single: {} placeholder intending to come back to it; copies a mapping from another unit and removes the value lines; sets 'numeric:' with no value.
Related errors
- Phrase '{path}' must define forms.
- Phrase '{path}' must define a scalar string or an explicit '
- Phrase '{path}' must define forms, 'symbol', or 'template'.
- Phrase forms '{path}' must define at least one form.
- Phrase '{path}.countPlacement' uses unsupported count placem
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/b91ec6e7c784e414.
Report an issue: GitHub.