Humanizr/Humanizer · error · NotSupportedException
Culture '{Culture.Name}' does not support grammatical case '
Error message
Culture '{Culture.Name}' does not support grammatical case '{grammaticalCase}' for duration phrases. What it means
Thrown when the culture's case table exists and is applicable, but TryGetCase returns false for the specific GrammaticalCase requested. This means the locale supports some grammatical cases but not the particular one passed (for example a locale that has Nominative/Genitive/Dative but no Vocative). NotSupportedException is thrown with the offending case in the message; it is a per-locale, per-case coverage gap.
Source
Thrown at src/Humanizer/Localisation/Formatters/DefaultFormatter.cs:170
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.");
}
var unitOverlay = caseOverlay.Units[(int)timeUnit];
return unitOverlay.Kind switch
{
LocalizedDurationCaseUnitKind.SameAsNominative => FormatCaseAwareNominative(timeUnit, unit),
LocalizedDurationCaseUnitKind.NotApplicable => throw new NotSupportedException(
$"Culture '{Culture.Name}' does not apply grammatical case '{grammaticalCase}' to duration unit '{timeUnit}'."),
LocalizedDurationCaseUnitKind.Unsupported => throw new NotSupportedException(
$"Culture '{Culture.Name}' does not support grammatical case '{grammaticalCase}' for duration unit '{timeUnit}'."),
_ => FormatCaseAwareTimeSpanPhrase(
timeUnit,
unit,
unitOverlay.Phrase!.Value)
};
}
View on GitHub (pinned to ffc2b77c0f)
Solutions
- Restrict the requested GrammaticalCase to those the locale actually supports (consult the locale's case table rather than the full enum).
- Catch NotSupportedException per-case and fall back to a supported case (often Nominative or Genitive) or the plain overload.
- Drive case selection from a locale-specific capability map instead of a global enum loop.
Example fix
// before
foreach (GrammaticalCase c in Enum.GetValues(typeof(GrammaticalCase)))
yield return caseFormatter.TimeSpanHumanize(TimeUnit.Day, 1, c); // throws on unsupported case
// after
foreach (GrammaticalCase c in Enum.GetValues(typeof(GrammaticalCase)))
{
try { yield return caseFormatter.TimeSpanHumanize(TimeUnit.Day, 1, c); }
catch (NotSupportedException) { /* skip unsupported case for this locale */ }
} Defensive patterns
Strategy: try-catch
Validate before calling
// Per-locale case coverage varies; without the internal table you cannot // pre-check. If you have the data, validate that the locale's case table // contains the requested GrammaticalCase before calling.
Type guard
// Approximate guard using a locale-specific case allow-list:
static bool LocaleSupportsCase(CultureInfo c, GrammaticalCase gCase) =>
LocaleCaseCapabilities.TryGetValue(c.TwoLetterISOLanguageName, out var set) && set.Contains(gCase); Try / catch
try { return caseFormatter.TimeSpanHumanize(unit, count, gCase); }
catch (NotSupportedException ex) when (ex.Message.Contains("grammatical case"))
{ return caseFormatter.TimeSpanHumanize(unit, count, GrammaticalCase.Nominative); } Prevention
- Do not enumerate all GrammaticalCase values blindly across locales.
- Drive case selection from a locale-specific capability map.
- Fall back to Nominative or Genitive when the requested case is unsupported.
When it happens
Trigger: Requesting GrammaticalCase.Vocative from a locale whose case table omits vocative; iterating over all GrammaticalCase values and assuming each is supported; passing a case that is valid for one Slavic language but absent in another.
Common situations: Generic code enumerating GrammaticalCase.GetValues() and calling the formatter for each; copying a case from one locale's grammar to another where it does not exist; user-selectable case dropdown that lists every case regardless of locale.
Related errors
- Culture '{Culture.Name}' has no grammatical-case classificat
- Culture '{Culture.Name}' has an applicable grammatical case
- Culture '{Culture.Name}' does not support grammatical-case d
- 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/4fdfc2833bfb7b11.
Report an issue: GitHub.