twigphp/Twig · error · SyntaxError
Cannot use "extend" in a block.
Error message
Cannot use "extend" in a block.
What it means
Twig forbids placing an {% extends %} tag inside a {% block %}. A block is rendered within the child/parent rendering flow, and inheritance must be decided before any block is rendered, so checkExtendsTag throws a SyntaxError when blockDepth is non-zero.
Solutions
- Move {% extends %} to the very top of the template, outside any block
- Remove the extends if the template should be standalone
- Split into two templates: one that extends, one that only defines the block content
Example fix
// before
{% block content %}
{% extends 'base.html.twig' %}
{% endblock %}
// after
{% extends 'base.html.twig' %}
{% block content %}...{% endblock %} Defensive patterns
Strategy: validation
Validate before calling
if (preg_match('/{%-?\\s*extends\\b/', $blockBody)) { throw new \InvalidArgumentException('extends not allowed inside block'); } Try / catch
try { $env->render($name); } catch (\Twig\Error\SyntaxError $e) { /* 'extend' placement error */ } Prevention
- {% extends %} must be top-level and first in a template
- Never wrap whole templates in blocks
- Validate template sources before deployment
When it happens
Trigger: An {% extends %} tag nested inside a {% block %} ... {% endblock %} body; detected in checkExtendsTag (called from checkConfigTag) when $this->blockDepth > 0.
Common situations: Accidentally indenting {% extends %} inside a block during refactoring; generating templates programmatically and wrapping everything in a block; copy-pasting a whole template body (including its extends) into a block.
Related errors
- Calling the "parent" function outside of a block is…
- Calling the "parent" function on a template that does not…
- A template that extends another one cannot include content…
- Cannot use "extend" in a macro.
- Multiple extends tags are forbidden.
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/5d8de4e927a3322a.
Report an issue: GitHub.
Appendix: source
Thrown at src/NodeVisitor/CorrectnessNodeVisitor.php:190
}
}
private function checkConfigTag(ConfigNode $node): void
{
if ('extends' === $node->getNodeTag()) {
$this->checkExtendsTag($node);
}
if (!isset($this->rootNodes[$node])) {
trigger_deprecation('twig/twig', '3.28', 'Using the "%s" tag outside the root of a template is deprecated in %s at line %d.', $node->getNodeTag(), $node->getSourceContext()->getName(), $node->getTemplateLine());
}
}
private function checkExtendsTag(ConfigNode $node): void
{
// "extends" inside a "block" or a "macro" has always been a hard error; keep it
if ($this->blockDepth) {
throw new SyntaxError('Cannot use "extend" in a block.', $node->getTemplateLine(), $node->getSourceContext());
}
if ($this->macroDepth) {
throw new SyntaxError('Cannot use "extend" in a macro.', $node->getTemplateLine(), $node->getSourceContext());
}
if ($this->hasExtends) {
throw new SyntaxError('Multiple extends tags are forbidden.', $node->getTemplateLine(), $node->getSourceContext());
}
$this->hasExtends = true;
}
private function checkBlockDefinitionNesting(BlockReferenceNode $node): void
{
// A "block" definition nested under an output-wrapping tag is registered globally
// regardless of that tag, so the nesting is misleading. This only matters at the root
// of a child template's body: once inside a block, a macro, an output capture, or in
// a standalone template, the block is rendered in place and behaves like any other.
if (!$this->hasParent || $this->blockDepth || $this->macroDepth || $this->capturingNodeDepth || !$this->tagStack) {View on GitHub (pinned to a414c3a491)