twigphp/Twig · error · SyntaxError
Unexpected " ".
Error message
Unexpected "%s".
What it means
Inside an expression, a closing bracket (`)`, `]`, or `}`) appeared when the bracket stack was empty — there is no matching opening bracket. Twig reports the offending character with line and column via checkBrackets, which runs for every punctuation token in lexExpression.
Solutions
- Remove the extra closing bracket at the reported line/column.
- Add the matching opening bracket if one was intended (e.g. `{{ foo(bar)) }}` → `{{ foo((bar)) }}` review).
- Wrap literal braces in `{% verbatim %}` blocks instead of leaving them in expressions.
- Re-check the whole expression — an earlier missing `(` often makes a later `)` look extra.
Example fix
// before
{{ items] }}
// after
{{ items }} Defensive patterns
Strategy: validation
Validate before calling
foreach (['(' => ')', '[' => ']', '{' => '}'] as $open => $close) {
if (preg_match('/\{\{[^}]*'.preg_quote($close, '/').'\s*\}\}/', $code)) {
// candidate stray closer inside an expression; review before parsing
}
} Try / catch
try {
$twig->render($name, $context);
} catch (\Twig\Error\SyntaxError $e) {
log('Unexpected bracket at line '.$e->getTemplateLine());
} Prevention
- Wrap literal braces/brackets in {% verbatim %} blocks.
- Re-read the whole expression — an extra closer usually mirrors an earlier missing opener.
- Use bracket-matching editor features when editing Twig expressions.
When it happens
Trigger: An extra `)` / `]` / `}` in a tag: e.g. `{{ foo) }}`, `{% if (x) %}` written as `{% if x) %}`, or a `}` inside `{{ }}` used literally without quoting. Also caused by a preceding unclosed-bracket removal that unbalanced the expression.
Common situations: Typos in arithmetic or function-call expressions; pasting PHP/JS expressions that use syntax Twig doesn't accept; literal braces in templates placed inside expression context instead of verbatim/raw blocks.
Related errors
- Unclosed " ".
- Unexpected character
- Unexpected end of file: Unclosed "verbatim" block.
- Unclosed comment.
- The lexer or the parser ended up in an unsupported state.
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/36f139ae375a0a67.
Report an issue: GitHub.
Appendix: source
Thrown at src/Lexer.php:670
private function popState(): void
{
if (0 === \count($this->states)) {
throw new \LogicException('Cannot pop state without a previous state.');
}
$this->state = array_pop($this->states);
}
private function checkBrackets(string $code): void
{
// opening bracket
if (\in_array($code, $this->openingBrackets, true)) {
$this->brackets[] = [$code, $this->lineno];
} elseif (\in_array($code, $this->closingBrackets, true)) {
// closing bracket
if (!$this->brackets) {
throw new SyntaxError(\sprintf('Unexpected "%s".', $code), $this->lineno, $this->source, columnno: $this->source->getColumn($this->cursor));
}
[$expect, $lineno] = array_pop($this->brackets);
if ($code !== str_replace($this->openingBrackets, $this->closingBrackets, $expect)) {
throw new SyntaxError(\sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
}
}
}
}
View on GitHub (pinned to a414c3a491)