{"record":{"id":"001d3a65851628da","repo":"symfony/symfony","slug":"the-strategy-attribute-of-the-twig-safe-class-001d3a","errorCode":null,"errorMessage":"The \"strategy\" attribute of the \"twig.safe_class\" tag on \"%s\" contains the invalid strategy \"%s\"; expected one of \"%s\" or a custom name matching \"[a-z][a-z0-9_]*\".","messagePattern":"The \"strategy\" attribute of the \"twig\\.safe_class\" tag on \"(.+?)\" contains the invalid strategy \"(.+?)\"; expected one of \"(.+?)\" or a custom name matching \"\\[a-z\\]\\[a-z0-9_\\]\\*\"\\.","errorType":"validation","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/SafeClassPass.php","lineNumber":57,"sourceCode":"    }\n\n    private function normalizeStrategies(array $tag, string $id): array\n    {\n        $strategies = $tag['strategy'] ?? null;\n        if (\\is_string($strategies)) {\n            $strategies = [$strategies];\n        } elseif (!\\is_array($strategies) || array_filter($strategies, 'is_string') !== $strategies) {\n            throw new InvalidArgumentException(\\sprintf('The \"strategy\" attribute of the \"twig.safe_class\" tag on \"%s\" must be a string or a list of strings.', $id));\n        } elseif (!$strategies) {\n            throw new InvalidArgumentException(\\sprintf('The \"strategy\" attribute of the \"twig.safe_class\" tag on \"%s\" must not be empty; use \"all\" to mark the class safe for every strategy.', $id));\n        }\n\n        foreach ($strategies as $strategy) {\n            if (\\in_array($strategy, self::BUILTIN_STRATEGIES, true)) {\n                continue;\n            }\n            if (!preg_match('/^[a-z][a-z0-9_]*$/D', $strategy)) {\n                throw new InvalidArgumentException(\\sprintf('The \"strategy\" attribute of the \"twig.safe_class\" tag on \"%s\" contains the invalid strategy \"%s\"; expected one of \"%s\" or a custom name matching \"[a-z][a-z0-9_]*\".', $id, $strategy, implode('\", \"', self::BUILTIN_STRATEGIES)));\n            }\n        }\n\n        return $strategies;\n    }\n}\n","sourceCodeStart":39,"sourceCodeEnd":64,"githubUrl":"https://github.com/symfony/symfony/blob/698e28026c22cf35d032cdb6e800db48b1535790/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/SafeClassPass.php#L39-L64","documentation":"Thrown by `SafeClassPass::normalizeStrategies()` when a strategy value is not one of the built-in strategies (`html`, `js`, `css`, `url`, `html_attr`, `html_attr_relaxed`, `all`) and also does not match the custom-name regex `[a-z][a-z0-9_]*`. This catches typos and invalid custom strategy names before they silently fail to escape.","triggerScenarios":"Tagging with `twig.safe_class` and a strategy like `HTML` (uppercase), `html-css` (hyphen), ` html` (leading space), or any value with uppercase/special chars. Line 56-57 validates the regex.","commonSituations":"Using uppercase or mixed-case strategy names. Adding a hyphen or space in a custom strategy. Typo like `htlm`.","solutions":["Use a built-in strategy name exactly as listed (`html`, `js`, `css`, `url`, `html_attr`, `html_attr_relaxed`, `all`).","For a custom strategy, use only lowercase letters, digits, and underscores, starting with a letter (e.g. `my_custom`).","Correct the typo to the intended built-in name."],"exampleFix":"# before\nservices:\n    App\\Widget:\n        tags:\n            - { name: twig.safe_class, strategy: HTML }\n# after\nservices:\n    App\\Widget:\n        tags:\n            - { name: twig.safe_class, strategy: html }","handlingStrategy":"validation","validationCode":"const BUILTIN = ['html','js','css','url','html_attr','html_attr_relaxed','all'];\nforeach ((array) $tag['strategy'] as $strategy) {\n    if (!in_array($strategy, BUILTIN, true) && !preg_match('/^[a-z][a-z0-9_]*$/D', $strategy)) {\n        throw new \\InvalidArgumentException(sprintf('Invalid strategy \"%s\"', $strategy));\n    }\n}","typeGuard":"function isValidStrategyName(string $s): bool\n{\n    $builtin = ['html','js','css','url','html_attr','html_attr_relaxed','all'];\n    return in_array($s, $builtin, true) || (bool) preg_match('/^[a-z][a-z0-9_]*$/D', $s);\n}","tryCatchPattern":null,"preventionTips":["Use lowercase strategy names only.","Stick to built-in names unless you have a real custom escaper.","Custom names must match [a-z][a-z0-9_]*."],"tags":["twig","di-compile","configuration","escaping","service-tag"],"analyzedSha":"698e28026c22cf35d032cdb6e800db48b1535790","analyzedAt":"2026-08-06T23:40:49.025Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}