Humanizr/Humanizer · error · InvalidOperationException
Release duration-case locales must use the explicit inventor
Error message
Release duration-case locales must use the explicit inventory, reason, sources, and provenance contract: {string.Join(", ", legacyCatalogs)}. What it means
Thrown by DurationCaseCoverageInput.Create when one or more release locales have a DurationCaseCatalog with empty Sources. Release locales must include the explicit provenance contract — inventory, reason, sources, and provenance — so that duration-case data is traceable. The error message lists every offending locale code.
Source
Thrown at src/Humanizer.SourceGenerators/Common/DurationCaseModels.cs:168
DurationCaseClassification.NotApplicable => "not-applicable",
_ => "unsupported"
}
: locale.VariantOf is not null
? "same-language-inherited"
: throw new InvalidOperationException(
$"Locale '{locale.LocaleCode}' has no authored or same-language inherited durationCases classification."),
locale.VariantOf));
}
var immutableCatalogs = catalogs.MoveToImmutable();
var legacyCatalogs = immutableCatalogs
.Where(static catalog => catalog.Sources.IsEmpty)
.Select(static catalog => catalog.LocaleCode)
.OrderBy(static locale => locale, StringComparer.Ordinal)
.ToArray();
if (legacyCatalogs.Length > 0)
{
throw new InvalidOperationException(
$"Release duration-case locales must use the explicit inventory, reason, sources, and provenance contract: {string.Join(", ", legacyCatalogs)}.");
}
var unsupportedPathBuilder = ImmutableArray.CreateBuilder<string>();
foreach (var catalog in immutableCatalogs)
{
unsupportedPathBuilder.AddRange(GetUnsupportedPaths(catalog));
}
var unsupportedPaths = unsupportedPathBuilder
.OrderBy(static path => path, StringComparer.Ordinal)
.ToArray();
if (unsupportedPaths.Length > 0)
{
throw new InvalidOperationException(
$"Release duration-case completeness requires zero unsupported dispositions; found {unsupportedPaths.Length}: {string.Join(", ", unsupportedPaths)}.");
}
View on GitHub (pinned to ffc2b77c0f)
Solutions
- Convert the locale's durationCases block to the explicit format with inventory, sources, reason, and provenance keys.
- For not-applicable classifications, provide a reason and provenance block with at least one source.
- Run the locale through ParseForTests locally to verify it routes to ParseExplicit (not ParseLegacyForTests) by including inventory or sources keys.
Example fix
# before (legacy format, no sources)
durationCases:
classification: distinct
cases:
genitive: { ... }
# after (explicit format with provenance)
durationCases:
classification: distinct
citationCase: nominative
inventory: [nominative, genitive]
sources:
- citation: 'Reference Grammar'
locator: 'p.123'
reason: 'Russian inflects duration units.'
provenance:
revision: '1'
locator: 'src/...'
credit: 'Author'
cases:
genitive: { ... } Defensive patterns
Strategy: validation
Validate before calling
// Verify all release catalogs have non-empty sources before the batch check
static bool AllCatalogsHaveSources(ImmutableArray<DurationCaseCatalog> catalogs) =>
catalogs.All(c => !c.Sources.IsEmpty); Prevention
- Release locales must use the explicit durationCases format with sources/provenance.
- Never ship a locale parsed via the legacy path — it produces empty sources.
- Run DurationCaseCoverageInput.Create in CI to catch missing provenance before release.
When it happens
Trigger: After parsing all locale catalogs, Create filters for catalogs where catalog.Sources.IsEmpty, collects their LocaleCodes, and throws if any exist. This fires when a locale's durationCases block was parsed via the legacy path (which produces empty sources) instead of the explicit path.
Common situations: A locale's durationCases YAML uses the legacy format (classification + cases without inventory/sources/provenance) in a release build. The legacy format is only valid for tests, not for checked-in release locales. Also occurs when a contributor adds a new locale and copies a test fixture's durationCases block.
Related errors
- Locale '{locale.LocaleCode}' must classify the durationCases
- Locale '{locale.LocaleCode}' has no authored or same-languag
- Release duration-case completeness requires zero unsupported
- '{path}' must use the explicit inventory, reason, sources, a
- '{path}' must define provenance.
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/3b774b5d230b96ff.
Report an issue: GitHub.