Humanizr/Humanizer · error · InvalidOperationException
Template '{path}' cannot use numeric placeholder '{{placehol
Error message
Template '{path}' cannot use numeric placeholder '{{placeholderName}}'. What it means
Thrown by CreateNamedTemplatePhrase when a template 'value' string contains a numeric placeholder like {0} or {1}. Humanizer templates use named placeholders (e.g. {count}, {unit}), never positional indices. Surfaced as compiler diagnostic HSG003 (severity Error).
Source
Thrown at src/Humanizer.SourceGenerators/Common/LocalePhraseNormalization.cs:446
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);
}
static NamedTemplatePhrase CreateNamedTemplatePhrase(string? templateName, string template, string path, params string[] allowedPlaceholders)
{
var placeholders = ImmutableArray.CreateBuilder<string>();
foreach (var placeholderName in GetPlaceholderNames(template))
{
if (int.TryParse(placeholderName, out _))
{
throw new InvalidOperationException($"Template '{path}' cannot use numeric placeholder '{{{placeholderName}}}'.");
}
if (placeholderName.Length == 0 || !char.IsLetter(placeholderName[0]) || placeholderName.Any(static c => !char.IsLetterOrDigit(c) && c != '_'))
{
throw new InvalidOperationException($"Template '{path}' uses unsupported placeholder '{{{placeholderName}}}'.");
}
if (!allowedPlaceholders.Contains(placeholderName, StringComparer.Ordinal))
{
throw new InvalidOperationException(
$"Template '{path}' can only use placeholders: {string.Join(", ", allowedPlaceholders.Select(static value => $"{{{value}}}"))}.");
}
if (!placeholders.Contains(placeholderName))
{
placeholders.Add(placeholderName);
}
}View on GitHub (pinned to ffc2b77c0f)
Solutions
- Replace numeric placeholders with the allowed named ones for that surface (e.g. {count}, {unit}, {value}, {prep}).
- Check the error's sibling message (149) which lists the placeholders permitted at that path.
- Rebuild to confirm the diagnostic clears.
Example fix
# before
template:
value: '{0} {1} ago'
# after
template:
value: '{count} {unit} ago' Defensive patterns
Strategy: validation
Validate before calling
# Reject numeric placeholders inside template values.
grep -nE 'template:.*\{[0-9]+\}' src/Humanizer/Locales/<code>.yml
# Also catch block-style: grep -nE 'value:.*\{[0-9]+\}' for value: lines. Prevention
- Use named placeholders only ({count}, {unit}, {value}, {prep}).
- Never copy string.Format patterns verbatim into locale YAML.
- Build after migrating format strings.
When it happens
Trigger: Authoring a template value with string.Format-style indices such as '{0} {1}' or '{0}'.
Common situations: Copy-paste from C# string.Format code; habit from other localization systems that use numeric placeholders; misunderstanding the template syntax.
Related errors
- Template '{path}' uses unsupported placeholder '{{placeholde
- Template '{path}' can only use placeholders: {allowedPlaceho
- Phrase '{path}' can only use placeholders in explicit 'templ
- Template '{path}' must define a scalar 'value'.
- Phrase '{path}' must define a scalar string or an explicit '
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/33138a23097a3a77.
Report an issue: GitHub.