{"record":{"id":"feee8fb7d340f162","repo":"Humanizr/Humanizer","slug":"culture-culture-name-has-an-applicable-grammat","errorCode":null,"errorMessage":"Culture '{Culture.Name}' has an applicable grammatical case system, but verified duration forms are unavailable.","messagePattern":"Culture '(.+?)' has an applicable grammatical case system, but verified duration forms are unavailable\\.","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/Humanizer/Localisation/Formatters/DefaultFormatter.cs","lineNumber":158,"sourceCode":"        }\n\n        if ((uint)grammaticalCase > (uint)GrammaticalCase.Causal)\n        {\n            throw new ArgumentOutOfRangeException(nameof(grammaticalCase), grammaticalCase, \"Unsupported grammatical case.\");\n        }\n\n        if ((uint)timeUnit > (uint)TimeUnit.Year)\n        {\n            throw new ArgumentOutOfRangeException(nameof(timeUnit), timeUnit, \"Unsupported time unit.\");\n        }\n\n        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        {","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer/Localisation/Formatters/DefaultFormatter.cs#L140-L176","documentation":"Thrown when the culture's case table exists (Resolve returned non-null) but its Classification is LocaleDurationCaseClassification.Unsupported. This means the locale has an applicable grammatical-case system in principle, but Humanizer has no verified duration forms for it, so the case-aware path refuses to guess. It is a NotSupportedException signalling incomplete locale data rather than a bad argument.","triggerScenarios":"Calling case-aware duration formatting for a locale whose case system is recognized but whose duration phrases have not been authored/verified; a partially-localized locale that was shipped before its duration case data was completed.","commonSituations":"Upgrading Humanizer and hitting a locale whose classification flipped to Unsupported due to a data review; using a locale that maps to a supported case family but lacks vetted duration forms; contributing a locale without finishing the duration case overlay.","solutions":["Fall back to the nominative TimeSpanHumanize(timeUnit, unit) overload when case-aware formatting is unsupported.","Catch NotSupportedException around the case-aware call and degrade gracefully to a non-cased phrase.","If you maintain the locale, complete its duration case data so the classification moves out of Unsupported."],"exampleFix":"// before\nvar text = caseFormatter.TimeSpanHumanize(TimeUnit.Hour, 3, GrammaticalCase.Genitive);\n\n// after\nstring text;\ntry { text = caseFormatter.TimeSpanHumanize(TimeUnit.Hour, 3, GrammaticalCase.Genitive); }\ncatch (NotSupportedException) { text = formatter.TimeSpanHumanize(TimeUnit.Hour, 3); }","handlingStrategy":"try-catch","validationCode":"// Classification is internal; pre-checking requires a locale allow-list.\n// Validate against your own set of locales with verified duration forms before calling.","typeGuard":"static readonly HashSet<string> VerifiedDurationLocales = new() { /* populate from your data */ };\nstatic bool LocaleHasVerifiedDurations(CultureInfo c) =>\n    VerifiedDurationLocales.Contains(c.Name);","tryCatchPattern":"try { return caseFormatter.TimeSpanHumanize(unit, count, gCase); }\ncatch (NotSupportedException) { return formatter.TimeSpanHumanize(unit, count); }","preventionTips":["Maintain an allow-list of locales with complete duration case data.","Fall back to nominative when duration forms are unverified.","Track locale data completeness when upgrading Humanizer."],"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"}