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
- Ensure every value passed in the $macros array is a \Twig\Node\MacroNode instance.
- If wrapping other content, use the appropriate Node container (e.g. Node or ModuleNode) instead of MacrosNode.
- 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
- Type-hint arrays with docblocks @param array<string, MacroNode>
- Validate node maps before constructing AST containers
- Avoid manually assembling MacrosNode unless writing extensions
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
- A " " can only contain " " nodes; replacing the macro " "…
- The argument " " in macro " " cannot be defined because the…
- The variadic argument
- Argument " " is defined twice for macro " ".
- Expected endmacro for macro
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)