twigphp/Twig · error · InvalidArgumentException
" ::getOperators()" must return an array of 2 elements, got…
Error message
"%s::getOperators()" must return an array of 2 elements, got %d.
What it means
After confirming getOperators() returns an array, Twig requires exactly two elements: element [0] is unary operators, element [1] is binary operators. This InvalidArgumentException fires when the array has any other count (0, 1, 3, ...), typically because unary and binary were merged into one flat array or [unary, binary] was wrapped in an extra level.
Solutions
- Return exactly two array elements: [unaryOperators, binaryOperators], even if one is empty ([]).
- Check for extra wrapping levels: returning [[unary, binary]] counts as 1 element — flatten one level.
- Copy the structure from \Twig\Extension\CoreExtension::getOperators() as a reference.
- Upgrade or replace the incompatible third-party extension and add an initialization smoke test in CI.
Example fix
// before
class MyExtension extends AbstractExtension {
public function getOperators(): array { return [['bnot' => [...]]]; } // 1 element
}
// after
class MyExtension extends AbstractExtension {
public function getOperators(): array {
return [
['bnot' => ['precedence' => 50, 'class' => MyUnary::class]], // unary
[], // binary (may be empty)
];
}
} Defensive patterns
Strategy: validation
Validate before calling
$ops = $ext->getOperators();
if (!\is_array($ops) || \count($ops) !== 2 || !\is_array($ops[0]) || !\is_array($ops[1])) {
throw new \UnexpectedValueException('getOperators() must return exactly [unaryOperators, binaryOperators]');
} Type guard
function hasTwoOperatorArrays(mixed $ops): bool {
return \is_array($ops) && 2 === \count($ops) && \is_array($ops[0]) && \is_array($ops[1]);
} Try / catch
try {
$twig->addExtension($ext);
$twig->loadTemplate('any.twig');
} catch (\InvalidArgumentException $e) {
if (str_contains($e->getMessage(), 'array of 2 elements')) {
// restructure getOperators() to the two-element [unary, binary] shape
}
throw $e;
} Prevention
- Always return a two-element array from getOperators(), using [] for an empty unary or binary set
- Do not wrap [unary, binary] in an extra array level; the count must be exactly 2
- Copy the structure from \Twig\Extension\CoreExtension::getOperators() as a template
- Pin and test extension versions against your Twig version in CI
When it happens
Trigger: getOperators() returns an array with fewer or more than 2 elements — returning only the unary operators array, merging unary and binary into a single map, or returning [[unary, binary]] which counts as 1 element. Fires during initExtensions(), triggered by the first template load/render after adding the extension.
Common situations: Custom extensions written against outdated documentation; third-party extension incompatible with the installed Twig version; refactoring that flattened the [unary, binary] structure; returning [[unary, binary], extra] after wrapping.
Related errors
- getTokenParsers() must return an array of…
- " ::getOperators()" must return an array with operators…
- Unable to add a token parser as extensions have already…
- Unable to add test " " as extensions have already been…
- The "format_list" filter requires the "IntlListFormatter"…
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/ea80eb8ee9bd02ab.
Report an issue: GitHub.
Appendix: source
Thrown at src/ExtensionSet.php:513
}
// 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'])) {
$expressionParsers[] = $this->convertInfixExpressionParser($op['class'], $operator, $op['precedence'], $op['associativity'], $op['precedence_change'] ?? null, $op['aliases'] ?? [], $op['callable']);
} else {
$expressionParsers[] = new BinaryOperatorExpressionParser($op['class'], $operator, $op['precedence'], $op['associativity'], $op['precedence_change'] ?? null, '', $op['aliases'] ?? []);
}View on GitHub (pinned to a414c3a491)