{"record":{"id":"195d05e5ea474e45","repo":"Humanizr/Humanizer","slug":"locale-locale-localecode-must-classify-the-dur","errorCode":null,"errorMessage":"Locale '{locale.LocaleCode}' must classify the durationCases surface.","messagePattern":"Locale '(.+?)' must classify the durationCases surface\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Humanizer.SourceGenerators/Common/DurationCaseModels.cs","lineNumber":132,"sourceCode":"        public static DurationCaseCoverageInput Create(LocaleCatalogInput localeCatalog)\n        {\n            if (!localeCatalog.Diagnostics.IsEmpty)\n            {\n                throw new InvalidOperationException(\n                    string.Join(\n                        \"\\n\",\n                        localeCatalog.Diagnostics\n                            .Select(static diagnostic => diagnostic.GetMessage())\n                            .OrderBy(static message => message, StringComparer.Ordinal)));\n            }\n\n            var catalogs = ImmutableArray.CreateBuilder<DurationCaseCatalog>(localeCatalog.Locales.Length);\n            var rows = ImmutableArray.CreateBuilder<DurationCaseCoverageRow>(localeCatalog.Locales.Length);\n            foreach (var locale in localeCatalog.Locales)\n            {\n                if (!locale.ResolvedFeatures.TryGetValue(\"durationCases\", out var value))\n                {\n                    throw new InvalidOperationException(\n                        $\"Locale '{locale.LocaleCode}' must classify the durationCases surface.\");\n                }\n\n                locale.ResolvedFeatures.TryGetValue(\"phrases\", out var phrases);\n                var catalog = DurationCaseNormalization.Parse(\n                    locale.LocaleCode,\n                    value,\n                    GetExplicitDurationCaseNumberDetector(locale),\n                    phrases);\n                catalogs.Add(catalog);\n                rows.Add(new DurationCaseCoverageRow(\n                    locale.LocaleCode,\n                    locale.AuthoredFeatureNames.Contains(\"durationCases\")\n                        ? catalog.Classification switch\n                        {\n                            DurationCaseClassification.Distinct => \"distinct\",\n                            DurationCaseClassification.Invariant => \"invariant\",\n                            DurationCaseClassification.NotApplicable => \"not-applicable\",","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer.SourceGenerators/Common/DurationCaseModels.cs#L114-L150","documentation":"Thrown by DurationCaseCoverageInput.Create when iterating release locales and a locale's ResolvedFeatures dictionary has no 'durationCases' entry. Every locale shipped in a release must classify how duration units inflect by grammatical case — the generator cannot produce coverage tables without this classification.","triggerScenarios":"Create loops over localeCatalog.Locales and calls TryGetValue('durationCases'). If it returns false for any locale, this throws. This happens when a locale file omits the durationCases surface entirely and no parent locale provides it via inheritance resolution.","commonSituations":"A new locale is added without a durationCases surface block and without a variantOf parent that resolves one. Or an existing locale's durationCases block was accidentally deleted during editing. Release builds enforce completeness, so dev/preview locales that skip this will fail the release gate.","solutions":["Add a durationCases surface to the locale file with a classification (e.g. 'durationCases:\\n  classification: not-applicable' with reason/sources/provenance if it's a release locale).","If the locale is a variant, ensure its variantOf parent has a durationCases classification that resolves down.","For locales where duration cases don't apply, classify as 'not-applicable' with the required reason and provenance contract."],"exampleFix":"# before (no durationCases surface)\nsurfaces:\n  list:\n    engine: oxford\n# after\nsurfaces:\n  list:\n    engine: oxford\n  durationCases:\n    classification: not-applicable\n    reason: \"English does not inflect duration units by case.\"\n    sources: []\n    provenance: { ... }","handlingStrategy":"validation","validationCode":"// Ensure every release locale resolves a durationCases feature\nstatic bool AllLocalesHaveDurationCases(LocaleCatalogInput catalog) =>\n    catalog.Locales.All(locale => locale.ResolvedFeatures.ContainsKey(\"durationCases\"));","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Every release locale must have a durationCases surface or inherit one via variantOf.","Add durationCases to new locale files from the start.","Use 'classification: not-applicable' with reason/sources/provenance for languages without grammatical case."],"tags":["source-generator","locale","duration-cases","release-gate","completeness"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}