Humanizr/Humanizer · error · InvalidOperationException
Locale '{localeCode}.surfaces.clock.minuteWordsMap' defines
Error message
Locale '{localeCode}.surfaces.clock.minuteWordsMap' defines duplicate entries; choose either the dense or sparse form. What it means
`surfaces.clock.minuteWordsMap` can appear in either a dense (sequence) or sparse (numeric-keyed mapping) form, but not both — and the key must not be duplicated (CanonicalLocaleAuthoring.cs:256-260). Duplicate keys usually mean both forms were pasted in.
Source
Thrown at src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs:258
if (numberSurface.TryGetValue("formatting", out var fmtValue))
{
if (fmtValue is not SimpleYamlMapping fmtMapping)
{
throw new InvalidOperationException(
$"Locale '{localeCode}.surfaces.number.formatting' must be a mapping, not a scalar or sequence.");
}
ValidateNumberFormattingBlock(localeCode, fmtMapping);
features["numberFormatting"] = fmtMapping;
}
}
static SimpleYamlMapping NormalizeClockSurface(string localeCode, SimpleYamlMapping clockSurface)
{
if (clockSurface.DuplicateKeys.Contains("minuteWordsMap"))
{
throw new InvalidOperationException(
$"Locale '{localeCode}.surfaces.clock.minuteWordsMap' defines duplicate entries; choose either the dense or sparse form.");
}
if (!clockSurface.TryGetValue("minuteWordsMap", out var minuteWordsMap))
{
return clockSurface;
}
const string path = "surfaces.clock.minuteWordsMap";
SimpleYamlValue normalizedMinuteWordsMap = minuteWordsMap switch
{
SimpleYamlSequence sequence => NormalizeMinuteWordsSequence(localeCode, path, sequence),
SimpleYamlMapping mapping => NormalizeMinuteWordsMapping(localeCode, path, mapping),
_ => throw new InvalidOperationException(
$"Locale '{localeCode}.{path}' must be a sequence or sparse numeric mapping.")
};
var normalizedClockSurface = clockSurface.Values.ToBuilder();View on GitHub (pinned to ffc2b77c0f)
Solutions
- Keep exactly one minuteWordsMap entry: either the sequence or the sparse mapping.
- If you want a few overrides, prefer the sparse form with integer keys 0-59.
- Rebuild.
Example fix
# before
surfaces:
clock:
minuteWordsMap: [zero, five, ten]
minuteWordsMap:
15: "a quarter"
# after
surfaces:
clock:
minuteWordsMap:
15: "a quarter" Defensive patterns
Strategy: validation
Validate before calling
import yaml, sys
# PyYAML collapses duplicate keys; use the generator's SimpleYamlParser or grep:
text = open(sys.argv[1], encoding='utf-8').read()
assert text.count('minuteWordsMap:') <= 1, 'minuteWordsMap declared more than once' Prevention
- Author locales against the canonical schema; the error message lists the exact allowed names.
- Run `dotnet build src/Humanizer/Humanizer.csproj` locally so the generator reports locale errors before push.
- Copy an existing compliant locale file as your template rather than writing YAML from scratch.
When it happens
Trigger: The minuteWordsMap key appears twice in the clock surface (DuplicateKeys includes it), e.g. one sequence form and one mapping form.
Common situations: Merging two locale branches that each added minuteWordsMap; hand-editing and leaving the old form.
Related errors
- Locale '{localeCode}.{path}' must be a sequence or sparse nu
- Locale '{localeCode}.{path}' must contain at most 60 entries
- Locale '{localeCode}.{path}' defines duplicate key '{mapping
- Locale '{localeCode}.{path}' requires integer keys. Invalid
- Locale '{localeCode}.{path}' keys must be between 0 and 59.
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/6bfa9d8dc017843e.
Report an issue: GitHub.