Humanizr/Humanizer · error · InvalidOperationException

Phrase '{path}' must define a scalar string or an explicit '

Error message

Phrase '{path}' must define a scalar string or an explicit 'template'.

What it means

Thrown by GetOptionalLiteralOrExplicitTemplate (used for the duration 'age' field) when the value is a mapping that does not contain a 'template' key. The age field may be a scalar string or a mapping whose only key is 'template'. Surfaced as compiler diagnostic HSG003 (severity Error).

Source

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

        }

        static string? GetOptionalLiteralOrExplicitTemplate(SimpleYamlMapping mapping, string key, string path)
        {
            if (!mapping.TryGetValue(key, out var value))
            {
                return null;
            }

            if (value is SimpleYamlScalar scalar)
            {
                return ValidateLiteralText(path, scalar.Value);
            }

            var templateMapping = ExpectMapping(value, path);
            RejectUnknownKeys(templateMapping, path, ["template"]);
            if (!templateMapping.TryGetValue("template", out var templateValue))
            {
                throw new InvalidOperationException($"Phrase '{path}' must define a scalar string or an explicit 'template'.");
            }

            return ParseNamedTemplate(templateValue, $"{path}.template", ["value"]).Template;
        }

        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}}}'.");
                }

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Make age a scalar string, or a mapping containing exactly a 'template' entry.
  2. Remove the age key if the locale does not customize it.
  3. Rebuild to confirm the diagnostic clears.

Example fix

# before
duration:
  age:
    format: years
# after
duration:
  age:
    template:
      value: '{value} old'
Defensive patterns

Strategy: validation

Validate before calling

# The 'age' field must be a scalar or a mapping whose only key is 'template'.
yq -o=json '.phrases.duration.age | select(tag == "!!map" and (has("template") | not))' src/Humanizer/Locales/<code>.yml

Prevention

When it happens

Trigger: Authoring 'age:' as a mapping with keys other than template (or no keys at all), instead of a scalar or a { template: ... } block.

Common situations: Author tries to add extra metadata under age; mistyped the template key; left age: {} as a stub.

Related errors


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