twigphp/Twig · error · SyntaxError
The block ' ' has already been defined line .
Error message
The block '%s' has already been defined line %d.
What it means
Within one template, block names must be unique. Parser::setBlock throws this SyntaxError when a {% block %} with a name that was already defined is registered, reporting the line of the first definition. Duplicate blocks would make it ambiguous which content overrides the parent.
Solutions
- Rename the second block to a unique name
- Remove the duplicate block definition
- If you need repeated rendering of the same content, use {% include %} or a macro instead of a second block
- Uniquify generated block names (e.g. append an index) in code that builds templates
Example fix
// before
{% block title %}A{% endblock %}
{% block title %}B{% endblock %}
// after
{% block title %}A{% endblock %}
{% block subtitle %}B{% endblock %} Defensive patterns
Strategy: validation
Validate before calling
preg_match_all('/{%-?\\s*block\\s+([a-zA-Z_][a-zA-Z0-9_]*)/', $tpl, $m); if (count($m[1]) !== count(array_unique($m[1]))) { /* duplicate block names */ } Try / catch
try { $env->render($name); } catch (\Twig\Error\SyntaxError $e) { if (str_contains($e->getMessage(), 'already been defined')) { /* duplicate block */ } } Prevention
- Unique block names per template
- Rename blocks after copy-paste
- Uniquify generated block names in template builders
- Lint templates in CI
When it happens
Trigger: Defining {% block foo %} twice in the same template; a loop or include pattern that re-declares a block; programmatically building a template body that appends a block whose name already exists.
Common situations: Copy-pasting a block and forgetting to rename it; merging two templates that both define {block sidebar}; generating templates from data where block names are derived unsafely (e.g. from array keys that repeat).
Related errors
- A "block" tag cannot be under a
- A block must start with a tag name.
- A default value for an argument must be a constant (a…
- A template that extends another one cannot include content…
- An escaping strategy must be a string or false.
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/e638e557a381f454.
Report an issue: GitHub.
Appendix: source
Thrown at src/Parser.php:309
public function hasBlock(string $name): bool
{
trigger_deprecation('twig/twig', '3.12', 'Method "%s()" is deprecated.', __METHOD__);
return isset($this->blocks[$name]);
}
public function getBlock(string $name): Node
{
trigger_deprecation('twig/twig', '3.12', 'Method "%s()" is deprecated.', __METHOD__);
return $this->blocks[$name];
}
public function setBlock(string $name, BlockNode $value): void
{
if (isset($this->blocks[$name])) {
throw new SyntaxError(\sprintf("The block '%s' has already been defined line %d.", $name, $this->blocks[$name]->getTemplateLine()), $this->getCurrentToken()->getLine(), $this->blocks[$name]->getSourceContext());
}
$this->blocks[$name] = new BodyNode([$value], [], $value->getTemplateLine());
}
public function hasMacro(string $name): bool
{
trigger_deprecation('twig/twig', '3.12', 'Method "%s()" is deprecated.', __METHOD__);
return isset($this->macros[$name]);
}
public function setDocumentationTarget(Node $node): void
{
if (null === $index = array_key_last($this->documentationTargets)) {
throw new \LogicException('A documentation target can only be set while parsing a tag.');
}
if (null !== $this->documentationTargets[$index]) {View on GitHub (pinned to a414c3a491)