{"record":{"id":"4fdfc2833bfb7b11","repo":"Humanizr/Humanizer","slug":"culture-culture-name-does-not-support-grammati-4fdfc2","errorCode":null,"errorMessage":"Culture '{Culture.Name}' does not support grammatical case '{grammaticalCase}' for duration phrases.","messagePattern":"Culture '(.+?)' does not support grammatical case '(.+?)' for duration phrases\\.","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/Humanizer/Localisation/Formatters/DefaultFormatter.cs","lineNumber":170,"sourceCode":"        var table = LocaleDurationCaseTableCatalog.Resolve(Culture)\n            ?? throw new NotSupportedException(\n                $\"Culture '{Culture.Name}' has no grammatical-case classification for duration phrases.\");\n\n        if (table.Classification == LocaleDurationCaseClassification.Unsupported)\n        {\n            throw new NotSupportedException(\n                $\"Culture '{Culture.Name}' has an applicable grammatical case system, but verified duration forms are unavailable.\");\n        }\n\n        if (table.Classification == LocaleDurationCaseClassification.NotApplicable)\n        {\n            throw new NotSupportedException(\n                $\"Culture '{Culture.Name}' does not support grammatical-case duration phrases.\");\n        }\n\n        if (!table.TryGetCase(grammaticalCase, out var caseOverlay))\n        {\n            throw new NotSupportedException(\n                $\"Culture '{Culture.Name}' does not support grammatical case '{grammaticalCase}' for duration phrases.\");\n        }\n\n        var unitOverlay = caseOverlay.Units[(int)timeUnit];\n        return unitOverlay.Kind switch\n        {\n            LocalizedDurationCaseUnitKind.SameAsNominative => FormatCaseAwareNominative(timeUnit, unit),\n            LocalizedDurationCaseUnitKind.NotApplicable => throw new NotSupportedException(\n                $\"Culture '{Culture.Name}' does not apply grammatical case '{grammaticalCase}' to duration unit '{timeUnit}'.\"),\n            LocalizedDurationCaseUnitKind.Unsupported => throw new NotSupportedException(\n                $\"Culture '{Culture.Name}' does not support grammatical case '{grammaticalCase}' for duration unit '{timeUnit}'.\"),\n            _ => FormatCaseAwareTimeSpanPhrase(\n                timeUnit,\n                unit,\n                unitOverlay.Phrase!.Value)\n        };\n    }\n","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs#L152-L188","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nforeach (GrammaticalCase c in Enum.GetValues(typeof(GrammaticalCase)))\n    yield return caseFormatter.TimeSpanHumanize(TimeUnit.Day, 1, c); // throws on unsupported case\n\n// after\nforeach (GrammaticalCase c in Enum.GetValues(typeof(GrammaticalCase)))\n{\n    try { yield return caseFormatter.TimeSpanHumanize(TimeUnit.Day, 1, c); }\n    catch (NotSupportedException) { /* skip unsupported case for this locale */ }\n}","handlingStrategy":"try-catch","validationCode":"// Per-locale case coverage varies; without the internal table you cannot\n// pre-check. If you have the data, validate that the locale's case table\n// contains the requested GrammaticalCase before calling.","typeGuard":"// Approximate guard using a locale-specific case allow-list:\nstatic bool LocaleSupportsCase(CultureInfo c, GrammaticalCase gCase) =>\n    LocaleCaseCapabilities.TryGetValue(c.TwoLetterISOLanguageName, out var set) && set.Contains(gCase);","tryCatchPattern":"try { return caseFormatter.TimeSpanHumanize(unit, count, gCase); }\ncatch (NotSupportedException ex) when (ex.Message.Contains(\"grammatical case\"))\n{ return caseFormatter.TimeSpanHumanize(unit, count, GrammaticalCase.Nominative); }","preventionTips":["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."],"tags":["localization","grammatical-case","formatter","not-supported","culture"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}