{"record":{"id":"9fe50d45748eff90","repo":"Humanizr/Humanizer","slug":"phrase-path-must-define-a-scalar-string-or-an","errorCode":null,"errorMessage":"Phrase '{path}' must define a scalar string or an explicit 'template'.","messagePattern":"Phrase '(.+?)' must define a scalar string or an explicit 'template'\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Humanizer.SourceGenerators/Common/LocalePhraseNormalization.cs","lineNumber":505,"sourceCode":"        }\n\n        static string? GetOptionalLiteralOrExplicitTemplate(SimpleYamlMapping mapping, string key, string path)\n        {\n            if (!mapping.TryGetValue(key, out var value))\n            {\n                return null;\n            }\n\n            if (value is SimpleYamlScalar scalar)\n            {\n                return ValidateLiteralText(path, scalar.Value);\n            }\n\n            var templateMapping = ExpectMapping(value, path);\n            RejectUnknownKeys(templateMapping, path, [\"template\"]);\n            if (!templateMapping.TryGetValue(\"template\", out var templateValue))\n            {\n                throw new InvalidOperationException($\"Phrase '{path}' must define a scalar string or an explicit 'template'.\");\n            }\n\n            return ParseNamedTemplate(templateValue, $\"{path}.template\", [\"value\"]).Template;\n        }\n\n        static string ValidateLiteralText(string path, string text, params string[] allowedPlaceholders)\n        {\n            foreach (var placeholder in GetPlaceholderNames(text))\n            {\n                if (int.TryParse(placeholder, out _))\n                {\n                    throw new InvalidOperationException($\"Phrase '{path}' cannot use numeric placeholder '{{{placeholder}}}'.\");\n                }\n\n                if (placeholder.Length == 0 || !char.IsLetter(placeholder[0]) || placeholder.Any(static c => !char.IsLetterOrDigit(c) && c != '_'))\n                {\n                    throw new InvalidOperationException($\"Phrase '{path}' uses unsupported placeholder '{{{placeholder}}}'.\");\n                }","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer.SourceGenerators/Common/LocalePhraseNormalization.cs#L487-L523","documentation":"Thrown by GetOptionalLiteralOrExplicitTemplate (used for the duration 'age' field) when the value is a mapping that does not contain a 'template' key. The age field may be a scalar string or a mapping whose only key is 'template'. Surfaced as compiler diagnostic HSG003 (severity Error).","triggerScenarios":"Authoring 'age:' as a mapping with keys other than template (or no keys at all), instead of a scalar or a { template: ... } block.","commonSituations":"Author tries to add extra metadata under age; mistyped the template key; left age: {} as a stub.","solutions":["Make age a scalar string, or a mapping containing exactly a 'template' entry.","Remove the age key if the locale does not customize it.","Rebuild to confirm the diagnostic clears."],"exampleFix":"# before\nduration:\n  age:\n    format: years\n# after\nduration:\n  age:\n    template:\n      value: '{value} old'","handlingStrategy":"validation","validationCode":"# The 'age' field must be a scalar or a mapping whose only key is 'template'.\nyq -o=json '.phrases.duration.age | select(tag == \"!!map\" and (has(\"template\") | not))' src/Humanizer/Locales/<code>.yml","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer age as a scalar unless you need templating.","If mapping, include only 'template'.","Build to confirm."],"tags":["humanizer","source-generator","locale","yaml","localization","phrases","duration","age","template"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}