Humanizr/Humanizer · error · InvalidOperationException

Template '{path}' uses unsupported placeholder '{{placeholde

Error message

Template '{path}' uses unsupported placeholder '{{placeholderName}}'.

What it means

Thrown by CreateNamedTemplatePhrase when a template placeholder name is empty, does not start with a letter, or contains characters other than letters, digits, or underscore. Placeholder names must be valid identifiers. Surfaced as compiler diagnostic HSG003 (severity Error).

Source

Thrown at src/Humanizer.SourceGenerators/Common/LocalePhraseNormalization.cs:451

            }

            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);
                }
            }

            return new NamedTemplatePhrase(templateName, template, placeholders.ToImmutable());
        }

        static string? GetOptionalLiteral(SimpleYamlMapping mapping, string key, string path, params string[] allowedPlaceholders)

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Make each placeholder an identifier: start with a letter, use only letters/digits/underscores, no spaces.
  2. Use the underscore convention for multi-word placeholders if needed (e.g. {unit_count}), but prefer one of the allowed names.
  3. Rebuild to confirm the diagnostic clears.

Example fix

# before
template:
  value: '{ count } {unit}'
# after
template:
  value: '{count} {unit}'
Defensive patterns

Strategy: validation

Validate before calling

# Find malformed placeholders (empty, bad start char, illegal chars) in template values.
grep -nE 'value:.*\{(\s*|[^A-Za-z_][^}]*|[^}]*[^A-Za-z0-9_][^}]*)\}' src/Humanizer/Locales/<code>.yml

Prevention

When it happens

Trigger: Writing a template with a malformed placeholder such as '{}', '{ count}', '{1st}', '{count-unit}', or '{count!}'.

Common situations: Stray whitespace inside braces; using hyphens in placeholder names; leftover brace pairs from editing; markdown-style placeholders.

Related errors


AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13). Data as JSON: /api/errors/4354e57c08024916. Report an issue: GitHub.