{"record":{"id":"a777b9517c7922cd","repo":"twigphp/Twig","slug":"multiple-extends-tags-are-forbidden-parser","errorCode":null,"errorMessage":"Multiple extends tags are forbidden.","messagePattern":"Multiple extends tags are forbidden\\.","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"src/Parser.php","lineNumber":466,"sourceCode":"        return $this->parent || 0 < \\count($this->traits);\n    }\n\n    public function setParent(?Node $parent, bool $throwOnMultiple = true): void\n    {\n        if (null === $parent) {\n            trigger_deprecation('twig/twig', '3.12', 'Passing \"null\" to \"%s()\" is deprecated.', __METHOD__);\n        }\n\n        if (null !== $parent && !$parent instanceof AbstractExpression) {\n            trigger_deprecation('twig/twig', '3.24', 'Passing a \"%s\" instance to \"%s()\" is deprecated, pass an \"AbstractExpression\" instance instead.', $parent::class, __METHOD__);\n        }\n\n        if (null !== $this->parent) {\n            if (!$throwOnMultiple) {\n                return;\n            }\n\n            throw new SyntaxError('Multiple extends tags are forbidden.', $parent->getTemplateLine(), $parent->getSourceContext());\n        }\n\n        $this->parent = $parent;\n    }\n\n    public function getStream(): TokenStream\n    {\n        return $this->stream;\n    }\n\n    public function getCurrentToken(): Token\n    {\n        return $this->stream->getCurrent();\n    }\n\n    public function getFunction(string $name, int $line): TwigFunction\n    {\n        try {","sourceCodeStart":448,"sourceCodeEnd":484,"githubUrl":"https://github.com/twigphp/Twig/blob/a414c3a491defb5a60f2fc88ef79ff37c90010cd/src/Parser.php#L448-L484","documentation":"Parser::setParent records the template's parent from {% extends %}; if a parent was already set and $throwOnMultiple is true, a second extends tag is rejected with this SyntaxError. Inheritance must resolve to exactly one parent template.","triggerScenarios":"Two {% extends %} tags in one template (setParent called twice via getParser with throwOnMultiple=true); the legacy {% extends %} combined with an {% extends %} added by another extension or wrapper.","commonSituations":"Conditional inheritance attempts ({% if x %}{% extends 'a' %}{% else %}{% extends 'b' %}{% endif %}) — Twig parses both branches; template concatenation/merging; dynamic parent chosen with multiple extends statements instead of one expression.","solutions":["Use a single extends with a ternary: {% extends condition ? 'a.html.twig' : 'b.html.twig' %}","Delete the duplicate/leftover extends tag","Compute the parent in the controller/render call and pass it, keeping one extends with a variable: {% extends parent_template %}"],"exampleFix":"// before\n{% if admin %}{% extends 'admin_base.html' %}{% else %}{% extends 'base.html' %}{% endif %}\n// after\n{% extends admin ? 'admin_base.html' : 'base.html' %}","handlingStrategy":"validation","validationCode":"$n = preg_match_all('/{%-?\\\\s*extends\\\\b/', $tpl); if ($n > 1) { /* use one extends with ternary */ }","typeGuard":null,"tryCatchPattern":"try { $env->render($name); } catch (\\Twig\\Error\\SyntaxError $e) { if (str_contains($e->getMessage(), 'Multiple extends')) { /* fix template */ } }","preventionTips":["Single extends tag; choose parent via expression","Don't place extends inside {% if %} branches","Pass the parent template name as a render variable"],"tags":["twig","template-inheritance","syntax-error"],"backgroundTag":"invalid-template-structure","analyzedSha":"a414c3a491defb5a60f2fc88ef79ff37c90010cd","analyzedAt":"2026-09-13T15:10:46.849Z","contentChangedAt":"2026-09-13T15:10:46.849Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}