twigphp/Twig · error · InvalidArgumentException

Using " " for the macro " " of " " is not supported. You…

Error message

Using "%s" for the macro "%s" of "%s" is not supported. You must pass a "%s" instance.

What it means

MacrosNode's constructor validates that every entry in the $macros map is a MacroNode instance. Passing any other value (another Node type, a scalar, null) for a named macro slot is rejected with an InvalidArgumentException, because MacrosNode can only ever compile macro definitions.

Solutions

  1. Ensure every value passed in the $macros array is a \Twig\Node\MacroNode instance.
  2. If wrapping other content, use the appropriate Node container (e.g. Node or ModuleNode) instead of MacrosNode.
  3. Log/var_dump get_debug_type($macro) at the failing key to find which entry is wrong.

Example fix

// before
new \Twig\Node\MacrosNode(['greet' => new \Twig\Node\TextNode('hi')]);
// after
new \Twig\Node\MacrosNode(['greet' => new \Twig\Node\MacroNode(...)]);
Defensive patterns

Strategy: type-guard

Validate before calling

foreach ($macros as $name => $m) {
    if (!$m instanceof \Twig\Node\MacroNode) throw new InvalidArgumentException("$name is not a MacroNode");
}

Type guard

function isMacroMap(array $macros): bool {
    return array_every($macros, fn($m) => $m instanceof \Twig\Node\MacroNode);
}
// PHP has no array_every; use:
function isMacroMap(array $macros): bool { foreach ($macros as $m) { if (!$m instanceof \Twig\Node\MacroNode) return false; } return true; }

Try / catch

try {
    $macrosNode = new \Twig\Node\MacrosNode($macros);
} catch (\InvalidArgumentException $e) {
    // log and fix the offending macro entry
}

Prevention

When it happens

Trigger: Constructing `new MacrosNode(['name' => $somethingNotMacroNode])` — typically custom compiler extensions or node visitors building macro containers programmatically and passing the wrong node type.

Common situations: Writing a Twig extension that manipulates the AST; refactoring code that used to put raw Nodes into a MacrosNode; accidental map mixing where a non-macro node lands in the macros array.

Related errors


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

Appendix: source

Thrown at src/Node/MacrosNode.php:34

/**
 * Represents the macros declared in a template.
 *
 * It compiles to the method returning the macro registry of the template.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
#[YieldReady]
final class MacrosNode extends Node
{
    /**
     * @param array<string, MacroNode> $macros
     */
    public function __construct(array $macros = [])
    {
        foreach ($macros as $name => $macro) {
            if (!$macro instanceof MacroNode) {
                throw new \InvalidArgumentException(\sprintf('Using "%s" for the macro "%s" of "%s" is not supported. You must pass a "%s" instance.', get_debug_type($macro), $name, static::class, MacroNode::class));
            }
        }

        parent::__construct($macros);
    }

    public function setNode(string $name, Node $node): void
    {
        if (!$node instanceof MacroNode) {
            throw new \LogicException(\sprintf('A "%s" can only contain "%s" nodes; replacing the macro "%s" with a "%s" node is not supported.', static::class, MacroNode::class, $name, get_debug_type($node)));
        }

        parent::setNode($name, $node);
    }

    public function compile(Compiler $compiler): void
    {
        if (!\count($this)) {

View on GitHub (pinned to a414c3a491)