twigphp/Twig · error · LogicException

The "name" attribute must be a string.

Error message

The "name" attribute must be a string.

What it means

SetBinary compiles simple assignments ({{ x = expr }} style) and expects the left side to carry a string 'name' attribute identifying the target variable. If that attribute exists but isn't a string (e.g. it's an array, an expression node, or missing/Null produced earlier), the assignment target is malformed, so a LogicException is thrown.

Solutions

  1. Verify the left node's attribute: $left->getAttribute('name') must return a plain PHP string; fix the parser to emit a NameExpression (or setAttribute('name', (string) ...) at creation).
  2. Only construct SetBinary when the LHS parses to a bare variable; route complex LHS to the appropriate node (ArrayExpression pairs to ObjectDestructuringSetBinary, etc.).
  3. Reject/raise a SyntaxError at parse time for non-variable assignment targets instead of building SetBinary.
  4. Catch the LogicException in parser tests to catch the regression early.

Example fix

// before
$node = new SetBinary($someExpressionNode, $rhs, $line); // 'name' attr is not a string
// after
$name = $someExpressionNode->getAttribute('name');
if (!\is_string($name)) {
    throw new SyntaxError('Cannot assign to a non-variable target.', $line);
}
$node = new SetBinary($someExpressionNode, $rhs, $line);
Defensive patterns

Strategy: type-guard

Validate before calling

$name = $left->getAttribute('name');
if (!\is_string($name) || $name === '') {
    throw new \SyntaxError(sprintf('Assignment target must be a bare variable name, got %s.', get_debug_type($name)), $lineno);
}

Type guard

function isVariableTarget(\Twig\Node\Node $n): bool {
    return $n->hasAttribute('name') && \is_string($n->getAttribute('name'));
}

Try / catch

try {
    $node = new SetBinary($left, $right, $lineno);
} catch (\LogicException $e) {
    // LHS 'name' attribute wasn't a string — raise a SyntaxError pointing at the template line
}

Prevention

When it happens

Trigger: Constructing SetBinary with a left node whose 'name' attribute is not a string — typically a node type other than NameExpression (which stores 'name' as a string), or a node with 'name' set to an array/node from a custom parser; a custom operator/parser reusing SetBinary for non-variable targets.

Common situations: Custom Twig extensions implementing assignment-like operators that pass the wrong LHS node; template DSLs where an expression, not a bare variable name, appears on the left of '='; version drift where the parser previously guaranteed NameExpression LHS but a change altered node shapes.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at src/Node/Expression/Binary/SetBinary.php:33

use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Expression\Variable\AssignContextVariable;
use Twig\Node\Expression\Variable\ContextVariable;
use Twig\Node\Node;

/**
 * @author Fabien Potencier <fabien@symfony.com>
 */
class SetBinary extends AbstractBinary
{
    /**
     * @param ContextVariable    $left
     * @param AbstractExpression $right
     */
    public function __construct(Node $left, Node $right, int $lineno)
    {
        $name = $left->getAttribute('name');
        if (!\is_string($name)) {
            throw new \LogicException('The "name" attribute must be a string.');
        }
        $left = new AssignContextVariable($name, $left->getTemplateLine());

        parent::__construct($left, $right, $lineno);
    }

    public function operator(Compiler $compiler): Compiler
    {
        return $compiler->raw('=');
    }
}

View on GitHub (pinned to a414c3a491)