twigphp/Twig · error · InvalidArgumentException

" ::getOperators()" must return an array with operators…

Error message

"%s::getOperators()" must return an array with operators, got "%s".

What it means

During extension initialization Twig calls getOperators() and requires an array; this InvalidArgumentException means a non-array was returned. getOperators() must return an array of exactly two elements: [unaryOperators, binaryOperators]. The message includes the actual debug type (and value for scalars) to pinpoint the bad return.

Solutions

  1. Make getOperators() return exactly two arrays: return [$unaryOperators, $binaryOperators];
  2. Add an explicit array return type (public function getOperators(): array) so PHP rejects null/non-array returns early.
  3. Inspect what the extension actually returns (get_debug_type) and fix the offending return statement.
  4. Remove or upgrade the offending third-party extension to a version compatible with your Twig.

Example fix

// before
class MyExtension extends AbstractExtension {
    public function getOperators() { return ['~' => [...]]; } // flat map, not 2-element array
}

// after
class MyExtension extends AbstractExtension {
    public function getOperators(): array {
        return [
            ['not' => ['precedence' => 50, 'class' => \Twig\Node\Expression\Unary\NotUnary::class]],
            ['~' => ['precedence' => 30, 'class' => \Twig\Node\Expression\Binary\ConcatBinary::class]],
        ];
    }
}
Defensive patterns

Strategy: validation

Validate before calling

$ops = $ext->getOperators();
if (!\is_array($ops)) {
    throw new \UnexpectedValueException(get_class($ext).'::getOperators() must return [unary, binary] arrays, got '.get_debug_type($ops));
}

Type guard

function isArrayOperators(mixed $ops): bool {
    return \is_array($ops);
}

Try / catch

try {
    $twig->addExtension($ext);
    $twig->loadTemplate('any.twig');
} catch (\InvalidArgumentException $e) {
    if (str_contains($e->getMessage(), '::getOperators()')) {
        // inspect and fix the extension's getOperators() return value
    }
    throw $e;
}

Prevention

When it happens

Trigger: An extension's getOperators() returns null, false, a string, a Generator, or any non-array — e.g. returning the result of a helper that failed, returning a single merged operator array as an object, or an override without a return-type declaration silently returning null.

Common situations: Legacy extensions written for very old Twig APIs; hand-written extensions returning a single operator array instead of [unary, binary]; misconfigured third-party extensions after a Twig upgrade; overridden getOperators() with a code path that falls through without returning.

Related errors


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

Appendix: source

Thrown at src/ExtensionSet.php:509

                throw new \LogicException('getTokenParsers() must return an array of \Twig\TokenParser\TokenParserInterface.');
            }

            $this->parsers[$parser->getTag()] = $parser;
        }

        // node visitors
        foreach ($extension->getNodeVisitors() as $visitor) {
            $this->visitors[] = $visitor;
        }

        // expression parsers
        if (method_exists($extension, 'getExpressionParsers')) {
            $this->expressionParsers->add($extension->getExpressionParsers());
        }

        $operators = $extension->getOperators();
        if (!\is_array($operators)) {
            throw new \InvalidArgumentException(\sprintf('"%s::getOperators()" must return an array with operators, got "%s".', $extension::class, get_debug_type($operators).(\is_resource($operators) ? '' : '#'.$operators)));
        }

        if (2 !== \count($operators)) {
            throw new \InvalidArgumentException(\sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', $extension::class, \count($operators)));
        }

        $expressionParsers = [];
        foreach ($operators[0] as $operator => $op) {
            $expressionParsers[] = new UnaryOperatorExpressionParser($op['class'], $operator, $op['precedence'], $op['precedence_change'] ?? null, '', $op['aliases'] ?? []);
        }
        foreach ($operators[1] as $operator => $op) {
            $op['associativity'] = match ($op['associativity']) {
                1 => InfixAssociativity::Left,
                2 => InfixAssociativity::Right,
                default => throw new \InvalidArgumentException(\sprintf('Invalid associativity "%s" for operator "%s".', $op['associativity'], $operator)),
            };

            if (isset($op['callable'])) {

View on GitHub (pinned to a414c3a491)