{"record":{"id":"183e273f00e00119","repo":"twigphp/Twig","slug":"the-variadic-argument-s-in-macro-s-cannot-have-the-same-name","errorCode":null,"errorMessage":"The variadic argument \"%s\" in macro \"%s\" cannot have the same name as another argument.","messagePattern":"The variadic argument \"(.+?)\" in macro \"(.+?)\" cannot have the same name as another argument\\.","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"src/Node/MacroNode.php","lineNumber":68,"sourceCode":"\n        if (!$arguments instanceof ArrayExpression) {\n            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));\n\n            $args = new ArrayExpression([], $arguments->getTemplateLine());\n            foreach ($arguments as $n => $default) {\n                $args->addElement($default, new LocalVariable($n, $default->getTemplateLine()));\n            }\n            $arguments = $args;\n        }\n\n        $seen = [];\n        foreach ($arguments->getKeyValuePairs() as $pair) {\n            $argName = $pair['key']->getAttribute('name');\n            if (TempNameExpression::RESERVED_NAME_PREFIX.self::VARARGS_NAME === $argName) {\n                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());\n            }\n            if (null !== $variadicName && $variadicName === $this->stripReservedPrefix($argName)) {\n                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());\n            }\n            if (isset($seen[$argName])) {\n                throw new SyntaxError(\\sprintf('Argument \"%s\" is defined twice for macro \"%s\".', $this->stripReservedPrefix($argName), $name), $pair['value']->getTemplateLine(), $pair['value']->getSourceContext());\n            }\n            $seen[$argName] = true;\n        }\n\n        parent::__construct(['body' => $body, 'arguments' => $arguments], ['name' => $name, 'variadic_name' => $variadicName], $lineno);\n    }\n\n    public function compile(Compiler $compiler): void\n    {\n        // 4.0 cleanup: only an explicitly declared variadic (\"...name\") gets a trailing\n        // \"...$bucket\" parameter and a context entry; a non-variadic macro must NOT emit\n        // \"...$varargs\" anymore (so extra arguments raise an error), and the implicit\n        // \"varargs\" context entry and VARARGS_NAME handling below go away.\n        $variadicName = $this->getAttribute('variadic_name');\n        if (null === $variadicName) {","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/twigphp/Twig/blob/a414c3a491defb5a60f2fc88ef79ff37c90010cd/src/Node/MacroNode.php#L50-L86","documentation":"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.","triggerScenarios":"{% macro foo(a, ...args) %} combined with another argument also named 'args' (after Twig strips the internal reserved prefix) — variadicName equals a stripped argument name.","commonSituations":"Copy-pasting macro signatures where the variadic '...' name duplicates an existing parameter; refactoring a positional arg into the variadic without deleting the original.","solutions":["Rename the variadic parameter so it differs from all other macro arguments","Remove the now-duplicated plain argument"],"exampleFix":"// before\n{% macro render(item, extra, ...extra) %}...{% endmacro %}\n// after\n{% macro render(item, ...extra) %}...{% endmacro %}","handlingStrategy":"validation","validationCode":"$names = ['item', 'extra', 'extra']; // parsed macro args incl. variadic\nif (count($names) !== count(array_unique($names))) {\n    throw new InvalidArgumentException('Macro argument names must be unique');\n}","typeGuard":null,"tryCatchPattern":"try {\n    $twig->load('macros.html');\n} catch (\\Twig\\Error\\SyntaxError $e) {\n    // duplicate variadic name detected\n}","preventionTips":["Ensure variadic '...' names differ from all other parameters","Review macro signatures after refactor merges","Run template compile checks in CI"],"tags":["twig","macro","variadic","compile-time"],"backgroundTag":"duplicate-argument","analyzedSha":"a414c3a491defb5a60f2fc88ef79ff37c90010cd","analyzedAt":"2026-09-13T15:10:46.849Z","contentChangedAt":"2026-09-13T15:10:46.849Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}