Humanizr/Humanizer · error · InvalidOperationException
Phrase section '{path}' must be a mapping.
Error message
Phrase section '{path}' must be a mapping. What it means
Thrown by ExpectMapping when a YAML node that must be a mapping (object) is instead a scalar or sequence. Many phrase sections (relativeDate, duration, dataUnits, timeUnits, forms, template blocks) require mappings. Surfaced as compiler diagnostic HSG003 (severity Error).
Source
Thrown at src/Humanizer.SourceGenerators/Common/LocalePhraseNormalization.cs:544
{
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)
{
foreach (var key in mapping.Values.Keys.Where(key => !allowedKeys.Contains(key, StringComparer.Ordinal)))
{
throw new InvalidOperationException(
$"Phrase section '{path}' defines unsupported property '{key}'. Supported properties: {string.Join(", ", allowedKeys)}.");
}
}
}
}View on GitHub (pinned to ffc2b77c0f)
Solutions
- Restructure the node as a mapping with the expected keys (see the path in the message).
- If a scalar is genuinely intended, move it to the field that accepts scalars (e.g. a unit value rather than the duration section).
- Rebuild to confirm the diagnostic clears.
Example fix
# before
duration: hours
# after
duration:
hour:
forms:
default: hours Defensive patterns
Strategy: validation
Validate before calling
# Sections that must be mappings: relativeDate, duration, dataUnits, timeUnits, # past, future, forms, and any template block. Confirm their YAML tag is !!map. yq -o=json '[.phrases.relativeDate, .phrases.duration, .phrases.dataUnits, .phrases.timeUnits] | map(select(. != null and tag != "!!map"))' src/Humanizer/Locales/<code>.yml
Prevention
- Always follow a section key with nested keys on the next, deeper indentation line.
- Avoid flow-style scalars/lists for mapping sections.
- Build after structural changes.
When it happens
Trigger: Writing 'duration: hours' (scalar) where a mapping of unit keys is expected, or 'forms: [a, b]' (sequence) where a mapping of form keys is expected.
Common situations: Author oversimplifies a section into a scalar; misreads the schema; YAML flow-style mistake producing a sequence; indentation turning a mapping into a scalar sibling.
Related errors
- Phrase section '{path}' defines unsupported property '{key}'
- 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.
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/2f5315c962afc6f6.
Report an issue: GitHub.