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 unit '{timeUnit}'.

What it means

Thrown when a locale's duration case table marks a specific TimeUnit as Unsupported for the requested GrammaticalCase. This is a per-unit limitation: the culture supports the case in general (the earlier TryGetCase check passed), but this particular unit (e.g. Millisecond) has no case-inflected form. Reached only through the case-aware TimeSpanHumanize overloads that route into IGrammaticalCaseTimeSpanFormatter.TimeSpanHumanize.

Source

Thrown at src/Humanizer/Localisation/Formatters/DefaultFormatter.cs:180

        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)
        };
    }

    /// <inheritdoc/>
    public virtual string TimeSpanHumanize_Age()
    {
        return phraseTable.TimeSpanAge ?? "{0}";
    }

    /// <inheritdoc/>
    public virtual string DataUnitHumanize(DataUnit dataUnit, double count, bool toSymbol = true)
    {
        if (TryFormatDataUnitFromPhraseTable(dataUnit, count, toSymbol, out var generated))

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Omit the grammaticalCase argument for that unit so it renders in the nominative default (FormatCaseAwareNominative).
  2. Choose a locale whose case table marks the target unit Supported or SameAsNominative rather than Unsupported.
  3. Wrap the call and fall back to the non-case Humanize overload on NotSupportedException.

Example fix

// before
var s = ts.Humanize(2, TimeUnit.Day, culture: new CultureInfo("uk"), grammaticalCase: GrammaticalCase.Genitive);

// after — fall back to nominative when the case is unsupported for a unit
string s;
try
{
    s = ts.Humanize(2, TimeUnit.Day, culture: new CultureInfo("uk"), grammaticalCase: GrammaticalCase.Genitive);
}
catch (NotSupportedException)
{
    s = ts.Humanize(2, TimeUnit.Day, culture: new CultureInfo("uk"));
}
Defensive patterns

Strategy: try-catch

Validate before calling

// No public API exposes per-unit case support; validate by attempting the case-aware call and catching.
// If you know the locale, prefer the nominative default for units you have not verified:
var wantsCase = grammaticalCase != GrammaticalCase.Nominative;
// (no pre-check available — use try-catch below)

Try / catch

string rendered;
try
{
    rendered = ts.Humanize(maxUnit, minUnit, culture: culture, grammaticalCase: grammaticalCase);
}
catch (NotSupportedException)
{
    // Locale does not inflect this unit for the requested case; fall back to nominative.
    rendered = ts.Humanize(maxUnit, minUnit, culture: culture);
}

Prevention

When it happens

Trigger: Calling timeSpan.Humanize(..., grammaticalCase: GrammaticalCase.Instrumental) or the 3-arg Humanize(TimeSpan, GrammaticalCase) for a locale whose LocaleDurationCaseTable has Units[(int)timeUnit].Kind == LocalizedDurationCaseUnitKind.Unsupported. Distinct from line 171 (whole case absent); line 180 fires when the case exists but the specific unit is flagged Unsupported.

Common situations: Requesting an instrumental/dative/genitive case under a Slavic or Turkic locale that declines some duration units (day, hour) but marks others (millisecond, week) unsupported; assuming a locale that 'has cases' supports them on every TimeUnit.

Related errors


AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13). Data as JSON: /api/errors/16b3503211de65cf. Report an issue: GitHub.