twigphp/Twig · error · LogicException

EmptyNode cannot have children.

Error message

EmptyNode cannot have children.

What it means

EmptyNode is Twig's placeholder node representing 'nothing' (e.g. an omitted block of an if/for). As an intentional leaf, its setNode() is overridden to always throw: the compiler must never attach children to an EmptyNode. If you reach this, some code is trying to fill in a node slot that is supposed to stay empty.

Solutions

  1. Before calling setNode(), check the target is a real node: if (!$node instanceof EmptyNode) { $node->setNode(...); } and skip or replace the placeholder otherwise.
  2. Replace the EmptyNode with the concrete node type first (e.g. construct the intended Node and swap it via setNode on the PARENT, not on the EmptyNode).
  3. In a NodeVisitor, implement the swap in leaveNode() by returning a new node instead of mutating the EmptyNode.
  4. If this comes from a third-party extension, update the extension; EmptyNode's immutable no-children contract is by design.

Example fix

// before
$node->setNode('body', $newBody); // crashes when $node is EmptyNode
// after
if (!$node instanceof \Twig\Node\EmptyNode) {
    $node->setNode('body', $newBody);
}
Defensive patterns

Strategy: type-guard

Validate before calling

if ($node instanceof \Twig\Node\EmptyNode) {
    throw new \LogicException('Cannot attach children to an EmptyNode placeholder; replace the placeholder in its parent instead.');
}

Type guard

function isAttachableNode(\Twig\Node\Node $n): bool { return !$n instanceof \Twig\Node\EmptyNode; }

Try / catch

try {
    $node->setNode($name, $child);
} catch (\LogicException $e) {
    // swap the EmptyNode out at its parent instead of mutating it
}

Prevention

When it happens

Trigger: Calling ->setNode('...', $node) directly on an EmptyNode instance, or a NodeVisitor/compiler pass written by you or an extension that unconditionally assigns children to the node returned from a parse slot without checking it's an EmptyNode placeholder.

Common situations: Custom NodeVisitor mutating nodes without instanceof checks; custom expression parsers reusing EmptyNode as a generic container; a visitor that rewrites nodes in leaveNode() but hits the empty placeholder branch of a construct.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13). Data as JSON: /api/errors/e120a3ad10691d0c. Report an issue: GitHub.

Appendix: source

Thrown at src/Node/EmptyNode.php:31

use Twig\Attribute\YieldReady;

/**
 * Represents an empty node.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
#[YieldReady]
final class EmptyNode extends Node
{
    public function __construct(int $lineno = 0)
    {
        parent::__construct([], [], $lineno);
    }

    public function setNode(string $name, Node $node): void
    {
        throw new \LogicException('EmptyNode cannot have children.');
    }
}

View on GitHub (pinned to a414c3a491)