Humanizr/Humanizer · critical · InvalidOperationException
Locale '{localeCode}.{path}.{key}' must be a string.
Error message
Locale '{localeCode}.{path}.{key}' must be a string. What it means
Thrown by ValidateMinuteWordValue when a clock minute slot's value is not a YAML scalar string (it is a mapping, a sequence, or a non-string token). The minute-words table must map each integer key to a single human-readable string, so any structured value is rejected at build time.
Source
Thrown at src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs:351
}
ValidateMinuteWordValue(localeCode, path, entry.Key, entry.Value, allowEmpty: false);
normalizedValues[canonicalKey] = entry.Value;
}
return new SimpleYamlMapping(normalizedValues.ToImmutable());
}
static void ValidateMinuteWordValue(
string localeCode,
string path,
string key,
SimpleYamlValue value,
bool allowEmpty)
{
if (value is not SimpleYamlScalar scalar || !scalar.IsString)
{
throw new InvalidOperationException(
$"Locale '{localeCode}.{path}.{key}' must be a string.");
}
if (!allowEmpty && string.IsNullOrEmpty(scalar.Value))
{
throw new InvalidOperationException(
$"Locale '{localeCode}.{path}.{key}' must be a non-empty string. Omit unused sparse slots instead.");
}
}
static void ValidateNumberFormattingBlock(string localeCode, SimpleYamlMapping formatting)
{
foreach (var property in formatting.Values.Keys.Where(static property => property is not ("decimalSeparator" or "negativeSign" or "groupSeparator")))
{
throw new InvalidOperationException(
$"Locale '{localeCode}.surfaces.number.formatting' defines unsupported property '{property}'. Supported properties: decimalSeparator, negativeSign, groupSeparator.");
}
View on GitHub (pinned to ffc2b77c0f)
Solutions
- Replace the minute's value with a single inline string scalar, e.g. '5: five minutes'.
- Check indentation: the minute key and its value must sit on the same line or be a plain folded scalar, not a nested block.
- Re-run 'dotnet build' to confirm ValidateMinuteWordValue no longer fires for {path}.{key}.
Example fix
# before
minutes:
5:
word: five minutes
# after
minutes:
5: five minutes Defensive patterns
Strategy: validation
Validate before calling
# Ensure every minute value is a plain scalar, not a nested mapping/sequence. # In your editor, each line under 'minutes:' must read '<int>: <string>'.
Prevention
- Keep minute values inline: '5: five minutes', never a nested block.
- Run 'dotnet build' after editing the clock surface to catch non-scalar values early.
- Mirror the structure of a known-good locale (e.g. src/Humanizer/Locales/en.yml) when translating.
When it happens
Trigger: A locale YAML minute entry is indented as a nested mapping/sequence (e.g. '5:\n value: five') or is a quoted multi-line block, so SimpleYamlValue is not a SimpleYamlScalar with IsString. Detected at CanonicalLocaleAuthoring.cs:349-353.
Common situations: Pasting from a richer locale format that nests metadata under each minute; mis-indenting a YAML value so it becomes a child mapping; converting an array-based locale representation into the canonical mapping form.
Related errors
- Locale '{localeCode}.{path}' defines duplicate numeric minut
- Locale '{localeCode}.{path}.{key}' must be a non-empty strin
- Locale '{localeCode}.surfaces.number.formatting' defines uns
- Locale '{localeCode}.surfaces.number.formatting' must define
- Locale '{localeCode}.surfaces.number.formatting.{propertyNam
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/664d59ba748a3447.
Report an issue: GitHub.