Humanizr/Humanizer · error · InvalidOperationException
Phrase '{path}.countPlacement' uses unsupported count placem
Error message
Phrase '{path}.countPlacement' uses unsupported count placement '{value}'. What it means
Thrown by ParseCountPlacement when the 'countPlacement' value on a counted phrase is not one of the supported strings. Allowed values are: empty/before-form/before (BeforeForm), after-form/after (AfterForm), none (None). Surfaced as compiler diagnostic HSG003 (severity Error).
Source
Thrown at src/Humanizer.SourceGenerators/Common/LocalePhraseNormalization.cs:417
defaultValue ??= zero ?? singular ?? dual ?? paucal ?? plural ?? many;
if (defaultValue is null)
{
forms = null!;
return false;
}
forms = new PhraseForms(defaultValue, zero, singular, dual, paucal, plural, many);
return true;
}
static CountPlacement ParseCountPlacement(SimpleYamlMapping mapping, string path) =>
GetOptionalLiteral(mapping, "countPlacement", $"{path}.countPlacement") switch
{
null or "" or "before-form" or "before" => CountPlacement.BeforeForm,
"after-form" or "after" => CountPlacement.AfterForm,
"none" => CountPlacement.None,
var value => throw new InvalidOperationException($"Phrase '{path}.countPlacement' uses unsupported count placement '{value}'.")
};
static NamedTemplatePhrase ParseNamedTemplate(SimpleYamlValue value, string path, params string[] allowedPlaceholders)
{
if (value is SimpleYamlScalar scalar)
{
return CreateNamedTemplatePhrase(null, scalar.Value, path, allowedPlaceholders);
}
var mapping = ExpectMapping(value, path);
RejectUnknownKeys(mapping, path, ["name", "value"]);
var name = GetOptionalLiteral(mapping, "name", $"{path}.name");
if (!mapping.TryGetValue("value", out var templateValue) || templateValue is not SimpleYamlScalar templateScalar)
{
throw new InvalidOperationException($"Template '{path}' must define a scalar 'value'.");
}
return CreateNamedTemplatePhrase(name, templateScalar.Value, path, allowedPlaceholders);View on GitHub (pinned to ffc2b77c0f)
Solutions
- Set countPlacement to one of: 'before-form'/'before', 'after-form'/'after', or 'none'.
- Omit countPlacement entirely to accept the default (BeforeForm).
- Rebuild to confirm the diagnostic clears.
Example fix
# before
multiple:
countPlacement: pre
forms:
singular: hour
# after
multiple:
countPlacement: before
forms:
singular: hour Defensive patterns
Strategy: validation
Validate before calling
# countPlacement must be one of the allowed literals (or absent).
allowed=["before-form","before","after-form","after","none"]
yq -o=json '.. | select(has("countPlacement")) | .countPlacement | select(. != null and ([.] | index($$allowed) | not))' src/Humanizer/Locales/<code>.yml Prevention
- Memorize the three intents: before, after, none (or omit for the default 'before').
- Do not invent placement names.
- Build to confirm.
When it happens
Trigger: Setting countPlacement to an unrecognized string such as 'pre', 'post', 'middle', 'before_count', or a locale-translated word.
Common situations: Author guesses a placement name instead of consulting the schema; copy-paste from a different library's convention; leftover experimental value.
Related errors
- Phrase '{path}' must define forms, 'symbol', or 'template'.
- Phrase '{path}' must define forms.
- Phrase '{path}' must define 'numeric', 'text', or 'words'.
- Phrase forms '{path}' must define at least one form.
- Template '{path}' must define a scalar 'value'.
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/c235daf47490a760.
Report an issue: GitHub.