twigphp/Twig · error · SyntaxError
Argument " " is defined twice for " ".
Error message
Argument "%s" is defined twice for %s "%s".
What it means
During compilation of a function/filter/method call, Twig maps named arguments to callable parameters. This error is thrown when the same argument name appears twice in the call's named-argument node, i.e. the template author passed the same named argument more than once (or a name collides with a positional slot already filled). Twig rejects this unconditionally at compile time as a SyntaxError.
Solutions
- Remove the duplicate named argument from the template call
- If both values were intended, rename one or combine them
- If generating templates programmatically, deduplicate argument names before rendering
- Check the exact call signature with twig's debug output or the function's PHP signature to see accepted names
Example fix
// before (template)
{{ date(post.created_at, format='Y-m-d', format='d/m/Y') }}
// after
{{ date(post.created_at, format='Y-m-d') }} Defensive patterns
Strategy: validation
Validate before calling
// Twig (PHP) pre-check before compiling user templates
$names = [];
foreach ($node->getNode('arguments') as $key => $arg) {
if (\is_string($key)) {
if (isset($names[$key])) { throw new \RuntimeException("Duplicate argument '$key'"); }
$names[$key] = true;
}
} Try / catch
try {
$twig->parse($twig->tokenize(new \Twig\Source($template, 'index')));
} catch (\Twig\Error\SyntaxError $e) {
if (str_contains($e->getMessage(), 'is defined twice')) {
// surface template line: $e->getTemplateLine()
}
} Prevention
- Deduplicate named arguments when generating templates programmatically
- Never mix a named argument with the same-named positional slot
- Lint templates in CI with Twig's parser before deployment
When it happens
Trigger: A template like {{ date|date(format='d', format='m') }}, or calling a function with a named argument whose name is also claimed by an earlier positional argument, e.g. {{ range(1, low=2) }}. In getArguments(), the name is found in $parameters and its target position $pos is already occupied.
Common situations: Copy-pasted argument lists where a parameter was renamed but the old named argument left in place; dynamic templates generated by code that appends named arguments without deduplication; mixing positional and named arguments where a named argument repeats a positional one.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- You cannot assign a value to
- Cannot assign to " ", only variables can be assigned in…
- Cannot assign to " ", only variables can be assigned in…
- Positional arguments cannot be used after named arguments…
- Argument " " is defined twice for " ".
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/7908c3d6ade1752f.
Report an issue: GitHub.
Appendix: source
Thrown at src/Node/Expression/CallExpression.php:199
$names = [];
$missingArguments = [];
$optionalArguments = [];
$pos = 0;
foreach ($callableParameters as $callableParameter) {
$name = $this->normalizeName($callableParameter->name);
if (\PHP_VERSION_ID >= 80000 && 'range' === $callable) {
if ('start' === $name) {
$name = 'low';
} elseif ('end' === $name) {
$name = 'high';
}
}
$names[] = $name;
if (\array_key_exists($name, $parameters)) {
if (\array_key_exists($pos, $parameters)) {
throw new SyntaxError(\sprintf('Argument "%s" is defined twice for %s "%s".', $name, $callType, $callName), $this->getTemplateLine(), $this->getSourceContext());
}
if (\count($missingArguments)) {
throw new SyntaxError(\sprintf(
'Argument "%s" could not be assigned for %s "%s(%s)" because it is mapped to an internal PHP function which cannot determine default value for optional argument%s "%s".',
$name, $callType, $callName, implode(', ', $names), \count($missingArguments) > 1 ? 's' : '', implode('", "', $missingArguments)
), $this->getTemplateLine(), $this->getSourceContext());
}
$arguments = array_merge($arguments, $optionalArguments);
$arguments[] = $parameters[$name];
unset($parameters[$name]);
$optionalArguments = [];
} elseif (\array_key_exists($pos, $parameters)) {
$arguments = array_merge($arguments, $optionalArguments);
$arguments[] = $parameters[$pos];
unset($parameters[$pos]);
$optionalArguments = [];View on GitHub (pinned to a414c3a491)