{"record":{"id":"c105fe0cceab43d9","repo":"Humanizr/Humanizer","slug":"case-overlay-path-phrase-must-explicitly-defin","errorCode":null,"errorMessage":"Case overlay '{path}.phrase' must explicitly define singular and numeric multiple forms.","messagePattern":"Case overlay '(.+?)\\.phrase' must explicitly define singular and numeric multiple forms\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Humanizer.SourceGenerators/Common/DurationCaseModels.cs","lineNumber":786,"sourceCode":"                throw new InvalidOperationException(\n                    $\"'{path}' must define exactly one of phrase, sameRenderedAs, notApplicable, or unsupported.\");\n            }\n\n            if (mapping.TryGetValue(\"phrase\", out var phraseValue))\n            {\n                var provenance = ParseProvenance(mapping, path, required: true);\n                ValidateProvenance(provenance, sources, path);\n                ValidateReachableMultipleForms(\n                    phraseValue,\n                    $\"{path}.phrase\",\n                    requiredMultipleForms);\n                var phrase = LocalePhraseNormalization.ParseTimeSpanPhrase(\n                    phraseValue,\n                    $\"{path}.phrase\",\n                    preserveDuplicateForms: !requiredMultipleForms.IsEmpty);\n                if (phrase.Single is null || phrase.Multiple?.Forms is null)\n                {\n                    throw new InvalidOperationException(\n                        $\"Case overlay '{path}.phrase' must explicitly define singular and numeric multiple forms.\");\n                }\n\n                return new DurationCaseUnitRealization(\n                    DurationCaseRealizationKind.Authored,\n                    null,\n                    phrase,\n                    null,\n                    provenance);\n            }\n\n            if (mapping.GetScalar(\"sameRenderedAs\") is { } targetCase)\n            {\n                var provenance = ParseProvenance(mapping, path, required: true);\n                ValidateProvenance(provenance, sources, path);\n                return new DurationCaseUnitRealization(\n                    DurationCaseRealizationKind.SameRenderedAs,\n                    targetCase,","sourceCodeStart":768,"sourceCodeEnd":804,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer.SourceGenerators/Common/DurationCaseModels.cs#L768-L804","documentation":"Thrown after parsing a 'phrase' value inside a duration-case unit realization when the resulting TimeSpanPhrase object is missing either its singular form or its multiple forms collection. The parser requires both phrase.Single and phrase.Multiple?.Forms to be non-null because case-overlay realizations must fully author both number forms.","triggerScenarios":"A unit realization uses 'phrase:' but the phrase mapping omits the 'single' key or the 'multiple.forms' sub-mapping (or provides them in an incomplete/incorrect shape).","commonSituations":"A contributor writes a phrase with only a 'multiple' scalar string but no 'single', or forgets the 'forms' sub-key under 'multiple', or copies a base-phrase structure that is valid in phrases.duration (which tolerates partial forms) into a durationCases realization (which requires both).","solutions":["Inspect the phrase mapping at the reported path and verify it has a 'single' entry and a 'multiple' entry.","Ensure 'multiple' contains a 'forms' mapping (or is itself a mapping of named forms) so that phrase.Multiple.Forms is populated.","Rebuild to confirm both singular and multiple forms are parsed successfully."],"exampleFix":"# before\nsecond:\n  phrase:\n    single: jedna sekunda\n    multiple:\n      default: X sekund\n# after\nsecond:\n  phrase:\n    single: jedna sekunda\n    multiple:\n      forms:\n        default: X sekund\n        dual: dwie sekundy","handlingStrategy":"validation","validationCode":"# Validate that every phrase in a realization has both 'single' and 'multiple.forms'\n# Use a YAML parser (e.g. yq or python) before building:\n# python -c \"import yaml,sys; d=yaml.safe_load(open(sys.argv[1])); ...\"\n# Ensure each realization unit with 'phrase' has phrase.single and phrase.multiple.forms","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always include both 'single' and 'multiple.forms' when authoring a phrase in a duration-case realization.","Copy a known-good phrase block from an existing locale (e.g. src/Humanizer/Locales/pl.yml) as a template.","Build incrementally after adding each unit realization to catch missing-form errors early."],"tags":["humanizer","locale","yaml","source-generator","duration-cases","phrase","build-time"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}