twigphp/Twig · error · SyntaxError
The variadic argument
Error message
The variadic argument "%s" in macro "%s" cannot have the same name as another argument.
What it means
When a macro declares a variadic argument, its name must be unique among the macro's arguments. Twig compiles macro arguments into a fixed signature, so a variadic parameter colliding with a named parameter would be ambiguous and is rejected in MacroNode's constructor.
Solutions
- Rename the variadic parameter so it differs from all other macro arguments
- Remove the now-duplicated plain argument
Example fix
// before
{% macro render(item, extra, ...extra) %}...{% endmacro %}
// after
{% macro render(item, ...extra) %}...{% endmacro %} Defensive patterns
Strategy: validation
Validate before calling
$names = ['item', 'extra', 'extra']; // parsed macro args incl. variadic
if (count($names) !== count(array_unique($names))) {
throw new InvalidArgumentException('Macro argument names must be unique');
} Try / catch
try {
$twig->load('macros.html');
} catch (\Twig\Error\SyntaxError $e) {
// duplicate variadic name detected
} Prevention
- Ensure variadic '...' names differ from all other parameters
- Review macro signatures after refactor merges
- Run template compile checks in CI
When it happens
Trigger: {% macro foo(a, ...args) %} combined with another argument also named 'args' (after Twig strips the internal reserved prefix) — variadicName equals a stripped argument name.
Common situations: Copy-pasting macro signatures where the variadic '...' name duplicates an existing parameter; refactoring a positional arg into the variadic without deleting the original.
Related errors
- The argument " " in macro " " cannot be defined because the…
- Argument " " is defined twice for macro " ".
- The last parameter of
- Unknown " " configuration.
- Calling the "parent" function outside of a block is…
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/183e273f00e00119.
Report an issue: GitHub.
Appendix: source
Thrown at src/Node/MacroNode.php:68
if (!$arguments instanceof ArrayExpression) {
trigger_deprecation('twig/twig', '3.15', \sprintf('Not passing a "%s" instance as the "arguments" argument of the "%s" constructor is deprecated ("%s" given).', ArrayExpression::class, static::class, $arguments::class));
$args = new ArrayExpression([], $arguments->getTemplateLine());
foreach ($arguments as $n => $default) {
$args->addElement($default, new LocalVariable($n, $default->getTemplateLine()));
}
$arguments = $args;
}
$seen = [];
foreach ($arguments->getKeyValuePairs() as $pair) {
$argName = $pair['key']->getAttribute('name');
if (TempNameExpression::RESERVED_NAME_PREFIX.self::VARARGS_NAME === $argName) {
throw new SyntaxError(\sprintf('The argument "%s" in macro "%s" cannot be defined because the variable "%s" is reserved for arbitrary arguments.', self::VARARGS_NAME, $name, self::VARARGS_NAME), $pair['value']->getTemplateLine(), $pair['value']->getSourceContext());
}
if (null !== $variadicName && $variadicName === $this->stripReservedPrefix($argName)) {
throw new SyntaxError(\sprintf('The variadic argument "%s" in macro "%s" cannot have the same name as another argument.', $variadicName, $name), $pair['value']->getTemplateLine(), $pair['value']->getSourceContext());
}
if (isset($seen[$argName])) {
throw new SyntaxError(\sprintf('Argument "%s" is defined twice for macro "%s".', $this->stripReservedPrefix($argName), $name), $pair['value']->getTemplateLine(), $pair['value']->getSourceContext());
}
$seen[$argName] = true;
}
parent::__construct(['body' => $body, 'arguments' => $arguments], ['name' => $name, 'variadic_name' => $variadicName], $lineno);
}
public function compile(Compiler $compiler): void
{
// 4.0 cleanup: only an explicitly declared variadic ("...name") gets a trailing
// "...$bucket" parameter and a context entry; a non-variadic macro must NOT emit
// "...$varargs" anymore (so extra arguments raise an error), and the implicit
// "varargs" context entry and VARARGS_NAME handling below go away.
$variadicName = $this->getAttribute('variadic_name');
if (null === $variadicName) {View on GitHub (pinned to a414c3a491)