{"record":{"id":"ede2b9e0c7cd9e6d","repo":"Humanizr/Humanizer","slug":"phrase-path-uses-unsupported-placeholder-pl","errorCode":null,"errorMessage":"Phrase '{path}' uses unsupported placeholder '{{placeholder}}'.","messagePattern":"Phrase '(.+?)' uses unsupported placeholder '(.+?)\\}'\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Humanizer.SourceGenerators/Common/LocalePhraseNormalization.cs","lineNumber":522,"sourceCode":"            {\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                }\n\n                if (!allowedPlaceholders.Contains(placeholder, StringComparer.Ordinal))\n                {\n                    throw new InvalidOperationException(\n                        allowedPlaceholders.Length == 0\n                            ? $\"Phrase '{path}' can only use placeholders in explicit 'template' entries.\"\n                            : $\"Phrase '{path}' can only use placeholders: {string.Join(\", \", allowedPlaceholders.Select(static value => $\"{{{value}}}\"))}.\");\n                }\n            }\n\n            return text;\n        }\n\n        static IEnumerable<string> GetPlaceholderNames(string text) =>\n            PlaceholderRegex.Matches(text)\n                .Cast<Match>()\n                .Select(static match => match.Groups[\"name\"].Value);","sourceCodeStart":504,"sourceCodeEnd":540,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer.SourceGenerators/Common/LocalePhraseNormalization.cs#L504-L540","documentation":"Thrown by ValidateLiteralText when a literal phrase string contains a placeholder whose name is empty, does not start with a letter, or contains non-identifier characters. Literal placeholders must be valid identifiers. Surfaced as compiler diagnostic HSG003 (severity Error).","triggerScenarios":"Writing a literal with '{}', '{ count}', '{count-unit}', or '{count!}'.","commonSituations":"Stray whitespace or punctuation inside braces; hyphenated placeholder names; leftover brace pairs.","solutions":["Remove the malformed placeholder from the literal, or use only an allowed identifier placeholder where permitted.","Move dynamic formatting into an explicit 'template' entry if a placeholder is genuinely needed.","Rebuild to confirm the diagnostic clears."],"exampleFix":"# before\nforms:\n  default: '{ count } hours'\n# after\nforms:\n  default: hours","handlingStrategy":"validation","validationCode":"# Find malformed placeholders inside literal string fields.\ngrep -nE '(symbol|default|zero|singular|dual|paucal|plural|many|beforeCount|afterCount):.*\\{(\\s*|[^A-Za-z_][^}]*|[^}]*[^A-Za-z0-9_][^}]*)\\}' src/Humanizer/Locales/<code>.yml","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid placeholders in literals altogether.","If a brace is needed literally, quote the value and avoid the { } pattern.","Build after editing."],"tags":["humanizer","source-generator","locale","yaml","localization","phrases","placeholder","literal"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}