twigphp/Twig · error · SyntaxError
A "block" tag cannot be under a
Error message
A "block" tag cannot be under a "%s" tag (line %d).
What it means
In a template that extends another, a {% block %} tag cannot appear nested inside another tag's body (e.g. an {% if %}, {% for %}, or {% set %} block), because overridden blocks must be collectable statically at the template root. checkBlockDefinitionNesting throws this SyntaxError naming the offending parent tag and its line.
Solutions
- Move the {% block %} to the template's top level and move the condition INSIDE the block
- Replace the loop-of-blocks with a single block that loops internally
- If conditional inheritance is needed, make the block's content conditional instead of its definition
Example fix
// before
{% if show %}{% block sidebar %}...{% endblock %}{% endif %}
// after
{% block sidebar %}{% if show %}...{% endif %}{% endblock %} Defensive patterns
Strategy: validation
Validate before calling
if (str_contains($tpl, '{% extends') && preg_match('/{%-?\\s*(if|for|set|spaceless)[^}]*%}(?:(?!{%-?\\s*(if|for|set|spaceless)\\b|block\\b).)*{%-?\\s*block\\b/s', $tpl)) { /* block nested under another tag */ } Try / catch
try { $env->render($name); } catch (\Twig\Error\SyntaxError $e) { /* block nesting error */ } Prevention
- Blocks must be at the top level of extending templates
- Move conditions inside block bodies, not around block tags
- Don't define blocks inside loops
When it happens
Trigger: Defining {% block %} inside {% if %}, {% for %}, {% spaceless %}, {% set %} etc. in a template that has {% extends %}; the check only runs when hasParent is true and blockDepth/macroDepth/capturingNodeDepth are zero while the tag stack is non-empty.
Common situations: Conditional blocks like {% if x %}{% block sidebar %}...{% endif %} that worked in standalone templates; loops that define a block per iteration; refactoring child templates by wrapping blocks in control-flow tags.
Related errors
- Calling the "parent" function outside of a block is…
- Calling the "parent" function on a template that does not…
- Block " " is not defined in trait " ".
- A template that extends another one cannot include content…
- Cannot use "extend" in a block.
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/5ae79a4096ed878a.
Report an issue: GitHub.
Appendix: source
Thrown at src/NodeVisitor/CorrectnessNodeVisitor.php:213
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) {
return;
}
$tag = $this->tagStack[array_key_last($this->tagStack)];
throw new SyntaxError(\sprintf('A "block" tag cannot be under a "%s" tag (line %d).', $tag->getNodeTag(), $tag->getTemplateLine()), $node->getTemplateLine(), $node->getSourceContext());
}
/**
* Returns true if the node never outputs anything or if the output is empty.
*/
private function isEmptyOutputNode(Node $node): bool
{
if ($node instanceof NodeCaptureInterface) {
// a "block" tag in such a node will serve as a block definition AND be displayed in place as well
return true;
}
// Can the text be considered "empty" (only whitespace)?
if ($node instanceof TextNode) {
return $node->isBlank();
}
if (!$node instanceof BlockReferenceNode && $node instanceof NodeOutputInterface) {View on GitHub (pinned to a414c3a491)