Humanizr/Humanizer · error · InvalidOperationException
'{path}' must define all duration 'units'.
Error message
'{path}' must define all duration 'units'. What it means
Thrown by ParseCase when a case overlay entry (under durationCases.cases.<caseName>) does not contain a 'units' key. Every case overlay must define all eight duration units explicitly, so the parser rejects an entry that omits the units mapping entirely.
Source
Thrown at src/Humanizer.SourceGenerators/Common/DurationCaseModels.cs:1127
}
return new DurationCaseOverlay(units.ToImmutable());
}
static ImmutableDictionary<string, DurationCaseUnitRealization> EmptyUnitRealizations() =>
ImmutableDictionary<string, DurationCaseUnitRealization>.Empty.WithComparers(StringComparer.Ordinal);
static ImmutableDictionary<string, DurationCaseSource> EmptySources() =>
ImmutableDictionary<string, DurationCaseSource>.Empty.WithComparers(StringComparer.Ordinal);
static DurationCaseOverlay ParseCase(SimpleYamlValue value, string path)
{
var mapping = ExpectMapping(value, path);
RejectUnknownKeys(mapping, path, ["units"]);
if (!mapping.TryGetValue("units", out var unitsValue))
{
throw new InvalidOperationException($"'{path}' must define all duration 'units'.");
}
var unitsMapping = ExpectMapping(unitsValue, $"{path}.units");
RejectUnknownKeys(unitsMapping, $"{path}.units", TimeUnits);
var units = ImmutableDictionary.CreateBuilder<string, DurationCaseUnit>(StringComparer.Ordinal);
foreach (var unitName in TimeUnits)
{
if (!unitsMapping.TryGetValue(unitName, out var unitValue))
{
throw new InvalidOperationException(
$"'{path}.units' must explicitly define '{unitName}'.");
}
units[unitName] = ParseUnit(unitValue, $"{path}.units.{unitName}");
}
return new DurationCaseOverlay(units.ToImmutable());
}View on GitHub (pinned to ffc2b77c0f)
Solutions
- Add a 'units' mapping to the case overlay entry at the reported path.
- Populate it with all eight time units (millisecond, second, minute, hour, day, week, month, year), each specifying a phrase, sameAsNominative, or unsupported value.
- Rebuild to confirm the case overlay is accepted.
Example fix
# before (case overlay missing 'units')
accusative:
citation: Acc
# after
accusative:
units:
millisecond:
sameAsNominative: true
second:
sameAsNominative: true
minute:
sameAsNominative: true
hour:
sameAsNominative: true
day:
sameAsNominative: true
week:
sameAsNominative: true
month:
sameAsNominative: true
year:
sameAsNominative: true Defensive patterns
Strategy: validation
Validate before calling
# Verify every case overlay in durationCases.cases has a 'units' key
# python: for case_name, case in yaml['durationCases']['cases'].items():
# assert 'units' in case, f'case {case_name} missing units' Prevention
- When adding a case to the cases section, immediately add the 'units' mapping with all eight time units.
- Copy a complete case overlay block from an existing locale and adapt it.
- Build after adding each case to catch missing-units errors at the specific path.
When it happens
Trigger: A case overlay entry in the 'cases' section of durationCases lacks the 'units' key, so TryGetValue('units', ...) returns false.
Common situations: A contributor adds a new case to the cases section but only provides metadata or a partial structure without the units mapping. Also occurs when a contributor confuses the case-overlay format (which needs 'units') with the realization format (which uses discriminators like phrase/sameRenderedAs).
Related errors
- '{path}' must define exactly one of phrase, sameRenderedAs,
- Case overlay '{path}.phrase' must explicitly define singular
- Duration case phrases use unsupported plural rule '{pluralRu
- Case overlay '{path}' must explicitly define numeric multipl
- Case overlay '{path}.multiple.forms' must explicitly define
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/b5757bed2e0e8ec4.
Report an issue: GitHub.