twigphp/Twig · error · SyntaxError

Argument " " could not be assigned for " ( )" because it is…

Error message

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".

What it means

When a named argument targets an optional parameter of a PHP internal function (extension/built-in), Twig cannot introspect that function's default values via reflection, so it requires that earlier optional parameters be explicitly filled first. If optional arguments were skipped ($missingArguments is non-empty) when trying to assign the named one, compilation fails with this SyntaxError.

Solutions

  1. Provide all preceding optional arguments positionally before the named one
  2. Avoid named arguments for functions backed by PHP internals; pass all arguments positionally
  3. Wrap the internal function in a custom Twig function with explicit parameter defaults
  4. Check the mapped PHP function's signature and fill gaps

Example fix

// before (template)
{{ substr('hello', start=2) }}
// after
{{ substr('hello', 0, 2) }}
Defensive patterns

Strategy: validation

Validate before calling

$ref = new \ReflectionFunction('substr');
foreach ($ref->getParameters() as $p) {
    if ($p->isOptional() && $p->getDefaultValue() === null && !$p->isDefaultValueAvailable()) {
        // internal function: fill all preceding optional args explicitly
    }
}

Try / catch

try {
    $twig->render($template, $ctx);
} catch (\Twig\Error\SyntaxError $e) {
    if (str_contains($e->getMessage(), 'cannot determine default value')) {
        // rewrite call to use positional args
    }
}

Prevention

When it happens

Trigger: Calling a mapped PHP internal function (e.g. from an extension like twig's core functions using native PHP functions) with a named argument for an optional parameter while skipping a preceding optional parameter, e.g. {{ substr(haystack, offset=1) }} style calls where an earlier optional arg is missing.

Common situations: Named-argument usage on filters/functions backed by native PHP functions (str* functions, etc.); PHP version changes that alter which functions are introspectable; templates ported from userland callables to internal ones.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

        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 = [];
                ++$pos;
            } elseif ($callableParameter->isDefaultValueAvailable()) {
                $optionalArguments[] = new ConstantExpression($callableParameter->getDefaultValue(), -1);
            } elseif ($callableParameter->isOptional()) {

View on GitHub (pinned to a414c3a491)