Humanizr/Humanizer · error · NotSupportedException

The formatter for '{culture?.Name ?? CultureInfo.CurrentCult

Error message

The formatter for '{culture?.Name ?? CultureInfo.CurrentCulture.Name}' does not support grammatical-case-aware durations.

What it means

Thrown by FormatTimePart when a grammatical case is requested for word-based output but the culture's IFormatter does not implement IGrammaticalCaseTimeSpanFormatter. Not all locale formatters support case inflection; this guard prevents silent fallback to the uninflected form.

Source

Thrown at src/Humanizer/TimeSpanHumanizeExtensions.cs:916

                toSymbols,
                grammaticalCase)
            : null;

    internal static string FormatTimePart(
        IFormatter cultureFormatter,
        TimeUnit timeUnit,
        int amount,
        CultureInfo? culture,
        bool toWords,
        bool toSymbols,
        GrammaticalCase? grammaticalCase) =>
        toSymbols
            ? string.Concat(amount.ToString(culture ?? CultureInfo.CurrentCulture), cultureFormatter.TimeUnitHumanize(timeUnit))
            : grammaticalCase is null
                ? cultureFormatter.TimeSpanHumanize(timeUnit, amount, toWords)
                : cultureFormatter is IGrammaticalCaseTimeSpanFormatter caseFormatter
                    ? caseFormatter.TimeSpanHumanize(timeUnit, amount, grammaticalCase.Value)
                    : throw new NotSupportedException(
                        $"The formatter for '{culture?.Name ?? CultureInfo.CurrentCulture.Name}' does not support grammatical-case-aware durations.");

    static string HumanizeSinglePart(
        TimeSpan timeSpan,
        CultureInfo? culture,
        TimeUnit maxUnit,
        TimeUnit minUnit,
        bool toWords,
        bool toSymbols,
        GrammaticalCase? grammaticalCase)
    {
        var cultureFormatter = Configurator.GetFormatter(culture);
        foreach (var timeUnit in TimeUnits)
        {
            var timePart = GetTimeUnitPart(
                timeUnit,
                timeSpan,
                maxUnit,

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Use a culture whose formatter implements IGrammaticalCaseTimeSpanFormatter (e.g. Slavic locales).
  2. Pass grammaticalCase: null for locales without case support.
  3. Implement IGrammaticalCaseTimeSpanFormatter on your custom formatter.

Example fix

// before
var s = ts.HumanizeWithCase(GrammaticalCase.Genitive, precision: 3, culture: new CultureInfo("en"));

// after
var s = ts.HumanizeWithCase(GrammaticalCase.Genitive, precision: 3, culture: new CultureInfo("ru"));
// or omit case for English: ts.Humanize(precision: 3)
Defensive patterns

Strategy: type-guard

Validate before calling

static bool FormatterSupportsCase(IFormatter formatter) =>
    formatter is IGrammaticalCaseTimeSpanFormatter;

Type guard

static bool CanHumanizeCaseForCulture(CultureInfo? culture)
{
    var formatter = Configurator.GetFormatter(culture);
    return formatter is IGrammaticalCaseTimeSpanFormatter;
}

Prevention

When it happens

Trigger: Calling HumanizeWithCase or a case-aware humanize with a culture whose formatter (e.g. English DefaultFormatter) does not implement IGrammaticalCaseTimeSpanFormatter. The formatter's type is checked at line 914.

Common situations: Requesting Genitive or Dative case for English or another locale that doesn't inflect time units by case. Using a locale that only supports the base IFormatter interface. Passing a culture from user preference that lacks case support.

Related errors


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