twigphp/Twig · error · SyntaxError

When using set, you must have the same number of variables…

Error message

When using set, you must have the same number of variables and assignments.

What it means

A compile-time SyntaxError raised in SetTokenParser::parse: this is a generic arity-validation guard inside the parser. When a {% set %} tag assigns to multiple targets (e.g. {% set a, b = ... %}), the parser checks that the number of assignment targets equals the number of value expressions; the error fires when a template author writes mismatched counts, such as two variables but only one value expression, so Twig cannot pair each variable with its value.

Solutions

  1. Make the target list and value list the same length, e.g. '{% set a, b = 1, 2 %}'
  2. Assign a single array to one variable and index it afterwards if counts differ
  3. Use capture syntax ({% set a %}...{% endset %}) only for single targets

Example fix

// before
{% set firstName, lastName = user.fullName %}
// after
{% set firstName, lastName = user.firstName, user.lastName %}
Defensive patterns

Strategy: validation

Validate before calling

// Count targets vs values in set-with-= statements
if (preg_match('/\{%\s*set\s+([^=}%]+)\s*=\s*(.+?)\s*%}/', $src, $m)) {
    $targets = count(array_map('trim', explode(',', $m[1])));
    $values  = preg_match_all('/(?<![|\w])(?:[\'\"].*?[\'\"]|\w+(?:\([^)]*\))?)/', $m[2]);
    if ($targets !== $values) {
        throw new InvalidArgumentException('set targets and values must match in count.');
    }
}

Try / catch

try {
    $twig->render($template, $ctx);
} catch (SyntaxError $e) {
    if (str_contains($e->getMessage(), 'same number of variables and assignments')) {
        // surface authoring error back to template editor
    }
    throw $e;
}

Prevention

When it happens

Trigger: Writing '{% set a, b = [1] %}' (2 targets, 1 value) or '{% set a = 1, 2 %}' (1 target, 2 values); parse throws after comparing count($names) with count($values).

Common situations: Refactoring a set to add or remove a variable without updating the right-hand side; assuming array elements spread across multiple targets automatically.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at src/TokenParser/SetTokenParser.php:47

 *
 * @internal
 */
final class SetTokenParser extends AbstractTokenParser
{
    public function parse(Token $token): Node
    {
        $lineno = $token->getLine();
        $stream = $this->parser->getStream();
        $names = $this->parseAssignmentExpression();

        $capture = false;
        if ($stream->nextIf(Token::OPERATOR_TYPE, '=')) {
            $values = $this->parseMultitargetExpression();

            $stream->expect(Token::BLOCK_END_TYPE);

            if (\count($names) !== \count($values)) {
                throw new SyntaxError('When using set, you must have the same number of variables and assignments.', $stream->getCurrent()->getLine(), $stream->getSourceContext());
            }
        } else {
            $capture = true;

            if (\count($names) > 1) {
                throw new SyntaxError('When using set with a block, you cannot have a multi-target.', $stream->getCurrent()->getLine(), $stream->getSourceContext());
            }

            $stream->expect(Token::BLOCK_END_TYPE);

            $values = $this->parser->subparse([$this, 'decideBlockEnd'], true);
            $stream->expect(Token::BLOCK_END_TYPE);
        }

        return new SetNode($capture, $names, $values, $lineno);
    }

    public function decideBlockEnd(Token $token): bool

View on GitHub (pinned to a414c3a491)