Humanizr/Humanizer · error · InvalidOperationException
Phrase '{path}' can only use placeholders in explicit 'templ
Error message
Phrase '{path}' can only use placeholders in explicit 'template' entries. What it means
Thrown by ValidateLiteralText when a literal phrase string contains any placeholder but the field allows none (allowedPlaceholders is empty). Many literal fields (e.g. data-unit symbol, relativeDate now) are pure text and cannot interpolate; formatting belongs in an explicit 'template' entry. Surfaced as compiler diagnostic HSG003 (severity Error).
Source
Thrown at src/Humanizer.SourceGenerators/Common/LocalePhraseNormalization.cs:529
static string ValidateLiteralText(string path, string text, params string[] allowedPlaceholders)
{
foreach (var placeholder in GetPlaceholderNames(text))
{
if (int.TryParse(placeholder, out _))
{
throw new InvalidOperationException($"Phrase '{path}' cannot use numeric placeholder '{{{placeholder}}}'.");
}
if (placeholder.Length == 0 || !char.IsLetter(placeholder[0]) || placeholder.Any(static c => !char.IsLetterOrDigit(c) && c != '_'))
{
throw new InvalidOperationException($"Phrase '{path}' uses unsupported placeholder '{{{placeholder}}}'.");
}
if (!allowedPlaceholders.Contains(placeholder, StringComparer.Ordinal))
{
throw new InvalidOperationException(
allowedPlaceholders.Length == 0
? $"Phrase '{path}' can only use placeholders in explicit 'template' entries."
: $"Phrase '{path}' can only use placeholders: {string.Join(", ", allowedPlaceholders.Select(static value => $"{{{value}}}"))}.");
}
}
return text;
}
static IEnumerable<string> GetPlaceholderNames(string text) =>
PlaceholderRegex.Matches(text)
.Cast<Match>()
.Select(static match => match.Groups["name"].Value);
static SimpleYamlMapping ExpectMapping(SimpleYamlValue value, string path) =>
value as SimpleYamlMapping ??
throw new InvalidOperationException($"Phrase section '{path}' must be a mapping.");
static void RejectUnknownKeys(SimpleYamlMapping mapping, string path, params string[] allowedKeys)
{View on GitHub (pinned to ffc2b77c0f)
Solutions
- Remove the placeholder from the literal so it is plain text.
- If interpolation is required, add an explicit 'template' entry to that phrase (templates permit the surface's allowed placeholders).
- Rebuild to confirm the diagnostic clears.
Example fix
# before
dataUnits:
byte:
symbol: '{count} B'
# after
dataUnits:
byte:
symbol: B
template:
value: '{count} {unit}' Defensive patterns
Strategy: validation
Validate before calling
# Surfaces whose literals allow NO placeholders include data-unit 'symbol',
# relativeDate now/today/never, and duration 'zero'. Find any {placeholder} there.
grep -nE '(symbol|now|today|never|zero):.*\{[^}]+\}' src/Humanizer/Locales/<code>.yml Prevention
- Treat symbol/now/today/never/zero as static text.
- Move interpolation into an explicit 'template' entry on that phrase.
- Build after restructuring.
When it happens
Trigger: Writing 'symbol: {count} B' or 'now: {value}' on a surface whose literals take no placeholders.
Common situations: Author assumes all fields accept {count}; migrating from a format-string-based resource; copy-paste of a templated value into a literal slot.
Related errors
- Template '{path}' cannot use numeric placeholder '{{placehol
- Template '{path}' uses unsupported placeholder '{{placeholde
- Template '{path}' can only use placeholders: {allowedPlaceho
- Phrase '{path}' cannot use numeric placeholder '{{placeholde
- Phrase '{path}' uses unsupported placeholder '{{placeholder}
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/4230994941e04a68.
Report an issue: GitHub.