twigphp/Twig · error · SyntaxError

Positional arguments cannot be used after named arguments…

Error message

Positional arguments cannot be used after named arguments for %s "%s".

What it means

When Twig compiles a function/filter call, getArguments collects arguments in order. Once a named argument is seen, all subsequent positional arguments are ambiguous because they can no longer map to their natural positions, so a SyntaxError is thrown naming the callable type and name.

Solutions

  1. Move the positional arguments before any named arguments: `{{ range(1, 10) }}` or `{{ range(1, end=10) }}`.
  2. Convert ALL arguments after the first named one to named form: `{{ range(start=1, end=10) }}`.
  3. Check the callable's signature to get the correct parameter names before mixing styles.

Example fix

// before (template)
{{ range(start=1, 10) }}
// after
{{ range(1, 10) }}
Defensive patterns

Strategy: validation

Validate before calling

// Keep positional arguments contiguous at the start of a call.
// Bad:  foo(a=1, 2)
// Good: foo(2, a=1)  or  foo(a=1, b=2)
$call = 'range(start=1, 10)';
if (preg_match('/\w+\s*=\s*[^,]+,\s*[^\w=)}]/', $call)) {
    // suspicious mixed order — rewrite the call before rendering
}

Prevention

When it happens

Trigger: Templates like `{{ range(start=1, 10) }}` or `{{ 'x'|filter(arr, fn, foo=1) }}` — a named argument followed by an integer-keyed (positional) argument; also direct PHP construction of a CallExpression with arguments passed in that mixed order.

Common situations: Incrementally converting calls to named arguments and missing one positional leftover; copy-pasted snippets mixing both styles; macros/functions with many parameters where the author switched styles mid-call.

Related errors


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

Appendix: source

Thrown at src/Node/Expression/CallExpression.php:158

    /**
     * @deprecated since Twig 3.12, use Twig\Util\CallableArgumentsExtractor::getArguments() instead
     */
    protected function getArguments($callable, $arguments)
    {
        trigger_deprecation('twig/twig', '3.12', 'The "%s()" method is deprecated, use Twig\Util\CallableArgumentsExtractor::getArguments() instead.', __METHOD__);

        $callType = $this->getAttribute('type');
        $callName = $this->getAttribute('name');

        $parameters = [];
        $named = false;
        foreach ($arguments as $name => $node) {
            if (!\is_int($name)) {
                $named = true;
                $name = $this->normalizeName($name);
            } elseif ($named) {
                throw new SyntaxError(\sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $callType, $callName), $this->getTemplateLine(), $this->getSourceContext());
            }

            $parameters[$name] = $node;
        }

        $isVariadic = $this->getAttribute('twig_callable')->isVariadic();
        if (!$named && !$isVariadic) {
            return $parameters;
        }

        if (!$callable) {
            if ($named) {
                $message = \sprintf('Named arguments are not supported for %s "%s".', $callType, $callName);
            } else {
                $message = \sprintf('Arbitrary positional arguments are not supported for %s "%s".', $callType, $callName);
            }

            throw new \LogicException($message);

View on GitHub (pinned to a414c3a491)