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
- 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).
- Only construct SetBinary when the LHS parses to a bare variable; route complex LHS to the appropriate node (ArrayExpression pairs to ObjectDestructuringSetBinary, etc.).
- Reject/raise a SyntaxError at parse time for non-variable assignment targets instead of building SetBinary.
- 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
- Only build SetBinary when the LHS is a NameExpression with a string 'name'.
- Validate attribute types at parse time and raise SyntaxError with template line info instead.
- Add a parser test that assignment to non-variables produces a clean SyntaxError, not a LogicException.
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
- Left side must be ArrayExpression for object/mapping…
- EmptyNode cannot have children.
- A documentation target can only be set while parsing a tag.
- The documentation target for a tag can only be set once.
- The "format_list" filter requires the "IntlListFormatter"…
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)