Humanizr/Humanizer · error · NotSupportedException
Culture '{Culture.Name}' has no grammatical-case classificat
Error message
Culture '{Culture.Name}' has no grammatical-case classification for duration phrases. What it means
Thrown when LocaleDurationCaseTableCatalog.Resolve(Culture) returns null for the formatter's culture, meaning Humanizer has no grammatical-case classification data at all for that locale. This is a data-coverage gap: the case-aware duration path requires a registered case table, and none exists for the culture. It is a NotSupportedException, not an argument error, because the inputs are valid but the locale is unsupported.
Source
Thrown at src/Humanizer/Localisation/Formatters/DefaultFormatter.cs:153
{
if (GetType().Assembly != typeof(DefaultFormatter).Assembly)
{
throw new NotSupportedException(
$"Custom formatter type '{GetType().FullName}' must explicitly implement {nameof(IGrammaticalCaseTimeSpanFormatter)} to support grammatical-case-aware durations.");
}
if ((uint)grammaticalCase > (uint)GrammaticalCase.Causal)
{
throw new ArgumentOutOfRangeException(nameof(grammaticalCase), grammaticalCase, "Unsupported grammatical case.");
}
if ((uint)timeUnit > (uint)TimeUnit.Year)
{
throw new ArgumentOutOfRangeException(nameof(timeUnit), timeUnit, "Unsupported time unit.");
}
var table = LocaleDurationCaseTableCatalog.Resolve(Culture)
?? throw new NotSupportedException(
$"Culture '{Culture.Name}' has no grammatical-case classification for duration phrases.");
if (table.Classification == LocaleDurationCaseClassification.Unsupported)
{
throw new NotSupportedException(
$"Culture '{Culture.Name}' has an applicable grammatical case system, but verified duration forms are unavailable.");
}
if (table.Classification == LocaleDurationCaseClassification.NotApplicable)
{
throw new NotSupportedException(
$"Culture '{Culture.Name}' does not support grammatical-case duration phrases.");
}
if (!table.TryGetCase(grammaticalCase, out var caseOverlay))
{
throw new NotSupportedException(
$"Culture '{Culture.Name}' does not support grammatical case '{grammaticalCase}' for duration phrases.");View on GitHub (pinned to ffc2b77c0f)
Solutions
- Only call the case-aware (IGrammaticalCaseTimeSpanFormatter) path for locales known to ship case tables (typically Slavic/Baltic languages); otherwise use the standard TimeSpanHumanize overloads.
- Wrap case-aware calls in try/catch (NotSupportedException) and fall back to the nominative TimeSpanHumanize(timeUnit, unit).
- If you need case-aware output for an unsupported locale, contribute the locale's case data to Humanizer rather than forcing the API.
Example fix
// before
var caseFormatter = (IGrammaticalCaseTimeSpanFormatter)formatter;
var text = caseFormatter.TimeSpanHumanize(TimeUnit.Day, 2, GrammaticalCase.Genitive); // throws for en
// after
string text;
try
{
var caseFormatter = (IGrammaticalCaseTimeSpanFormatter)formatter;
text = caseFormatter.TimeSpanHumanize(TimeUnit.Day, 2, GrammaticalCase.Genitive);
}
catch (NotSupportedException)
{
text = formatter.TimeSpanHumanize(TimeUnit.Day, 2); // nominative fallback
} Defensive patterns
Strategy: try-catch
Validate before calling
// No public API exposes the catalog; the robust guard is to attempt the call // and fall back. If you control the locale set, restrict case-aware calls to // known case-bearing languages before invoking.
Type guard
static readonly HashSet<string> CaseAwareLocales = new() { "ru", "uk", "pl", "cs", "sk", "lt", "lv" };
static bool CultureHasCaseTables(CultureInfo c) =>
CaseAwareLocales.Contains(c.TwoLetterISOLanguageName); Try / catch
try { return caseFormatter.TimeSpanHumanize(unit, count, gCase); }
catch (NotSupportedException) { return formatter.TimeSpanHumanize(unit, count); } Prevention
- Gate case-aware calls on a known set of case-bearing locales.
- Always provide a nominative fallback when locale data may be missing.
- Do not assume every DefaultFormatter culture supports case-aware durations.
When it happens
Trigger: Constructing a DefaultFormatter for a culture without grammatical-case data and calling IGrammaticalCaseTimeSpanFormatter.TimeSpanHumanize; routing a locale that has no Slavic/Baltic-style case system through the case-aware API. The error is culture-driven, so reproducing it requires a specific Culture on the formatter.
Common situations: Calling case-aware duration formatting for Western locales (en, fr, de) where grammatical case does not apply; a request locale that resolves to a culture Humanizer has not equipped with case tables; assuming all DefaultFormatter cultures support case-aware durations.
Related errors
- Culture '{Culture.Name}' has an applicable grammatical case
- Culture '{Culture.Name}' does not support grammatical-case d
- Culture '{Culture.Name}' does not support grammatical case '
- Culture '{Culture.Name}' does not apply grammatical case '{g
- Custom formatter type '{GetType().FullName}' must explicitly
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/c844bdd337c5ad86.
Report an issue: GitHub.