{"record":{"id":"eff20f9cf6e58943","repo":"Humanizr/Humanizer","slug":"template-path-can-only-use-placeholders-allo","errorCode":null,"errorMessage":"Template '{path}' can only use placeholders: {allowedPlaceholders}.","messagePattern":"Template '(.+?)' can only use placeholders: (.+?)\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Humanizer.SourceGenerators/Common/LocalePhraseNormalization.cs","lineNumber":457,"sourceCode":"        {\n            var placeholders = ImmutableArray.CreateBuilder<string>();\n\n            foreach (var placeholderName in GetPlaceholderNames(template))\n            {\n                if (int.TryParse(placeholderName, out _))\n                {\n                    throw new InvalidOperationException($\"Template '{path}' cannot use numeric placeholder '{{{placeholderName}}}'.\");\n                }\n\n                if (placeholderName.Length == 0 || !char.IsLetter(placeholderName[0]) || placeholderName.Any(static c => !char.IsLetterOrDigit(c) && c != '_'))\n                {\n                    throw new InvalidOperationException($\"Template '{path}' uses unsupported placeholder '{{{placeholderName}}}'.\");\n                }\n\n                if (!allowedPlaceholders.Contains(placeholderName, StringComparer.Ordinal))\n                {\n                    throw new InvalidOperationException(\n                        $\"Template '{path}' can only use placeholders: {string.Join(\", \", allowedPlaceholders.Select(static value => $\"{{{value}}}\"))}.\");\n                }\n\n                if (!placeholders.Contains(placeholderName))\n                {\n                    placeholders.Add(placeholderName);\n                }\n            }\n\n            return new NamedTemplatePhrase(templateName, template, placeholders.ToImmutable());\n        }\n\n        static string? GetOptionalLiteral(SimpleYamlMapping mapping, string key, string path, params string[] allowedPlaceholders)\n        {\n            if (!mapping.TryGetValue(key, out var value))\n            {\n                return null;\n            }\n","sourceCodeStart":439,"sourceCodeEnd":475,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer.SourceGenerators/Common/LocalePhraseNormalization.cs#L439-L475","documentation":"Thrown by CreateNamedTemplatePhrase when a template uses a placeholder name that is syntactically valid but not in the allowed set for that surface. Each surface restricts templates to specific names (e.g. dataUnit/timeUnit templates allow count and unit; counted-phrase templates allow count, unit, prep). Surfaced as compiler diagnostic HSG003 (severity Error).","triggerScenarios":"Writing a data-unit template with '{value}' or '{name}', or a duration template (allowed placeholders: none) with any placeholder.","commonSituations":"Author reuses a placeholder valid on one surface on a different surface where it is not supported; assuming all surfaces share the same placeholder vocabulary.","solutions":["Read the diagnostic: it lists the allowed placeholders for that exact path.","Replace the disallowed placeholder with one from the allowed set, or remove it.","Rebuild to confirm the diagnostic clears."],"exampleFix":"# before (data unit template)\ndataUnits:\n  byte:\n    template:\n      value: '{value}'\n# after\ndataUnits:\n  byte:\n    template:\n      value: '{count} {unit}'","handlingStrategy":"validation","validationCode":"# Per-surface allowed placeholders:\n#   dataUnits/timeUnits templates: {count}, {unit}\n#   counted-phrase templates: {count}, {unit}, {prep}\n#   duration 'age' template: {value}\n# Review each template value against its surface's allow-list before building.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Learn the placeholder vocabulary per surface (the HSG003 message lists it).","Do not assume a placeholder valid on one surface works elsewhere.","Build after editing templates."],"tags":["humanizer","source-generator","locale","yaml","localization","phrases","template","placeholder"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}