{"record":{"id":"e638e557a381f454","repo":"twigphp/Twig","slug":"the-block-s-has-already-been-defined-line-d","errorCode":null,"errorMessage":"The block '%s' has already been defined line %d.","messagePattern":"The block '(.+?)' has already been defined line (.+?)\\.","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"src/Parser.php","lineNumber":309,"sourceCode":"\n    public function hasBlock(string $name): bool\n    {\n        trigger_deprecation('twig/twig', '3.12', 'Method \"%s()\" is deprecated.', __METHOD__);\n\n        return isset($this->blocks[$name]);\n    }\n\n    public function getBlock(string $name): Node\n    {\n        trigger_deprecation('twig/twig', '3.12', 'Method \"%s()\" is deprecated.', __METHOD__);\n\n        return $this->blocks[$name];\n    }\n\n    public function setBlock(string $name, BlockNode $value): void\n    {\n        if (isset($this->blocks[$name])) {\n            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());\n        }\n\n        $this->blocks[$name] = new BodyNode([$value], [], $value->getTemplateLine());\n    }\n\n    public function hasMacro(string $name): bool\n    {\n        trigger_deprecation('twig/twig', '3.12', 'Method \"%s()\" is deprecated.', __METHOD__);\n\n        return isset($this->macros[$name]);\n    }\n\n    public function setDocumentationTarget(Node $node): void\n    {\n        if (null === $index = array_key_last($this->documentationTargets)) {\n            throw new \\LogicException('A documentation target can only be set while parsing a tag.');\n        }\n        if (null !== $this->documentationTargets[$index]) {","sourceCodeStart":291,"sourceCodeEnd":327,"githubUrl":"https://github.com/twigphp/Twig/blob/a414c3a491defb5a60f2fc88ef79ff37c90010cd/src/Parser.php#L291-L327","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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"],"exampleFix":"// before\n{% block title %}A{% endblock %}\n{% block title %}B{% endblock %}\n// after\n{% block title %}A{% endblock %}\n{% block subtitle %}B{% endblock %}","handlingStrategy":"validation","validationCode":"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 */ }","typeGuard":null,"tryCatchPattern":"try { $env->render($name); } catch (\\Twig\\Error\\SyntaxError $e) { if (str_contains($e->getMessage(), 'already been defined')) { /* duplicate block */ } }","preventionTips":["Unique block names per template","Rename blocks after copy-paste","Uniquify generated block names in template builders","Lint templates in CI"],"tags":["twig","blocks","duplicate-definition","syntax-error"],"backgroundTag":"invalid-template-structure","analyzedSha":"a414c3a491defb5a60f2fc88ef79ff37c90010cd","analyzedAt":"2026-09-13T15:10:46.849Z","contentChangedAt":"2026-09-13T15:10:46.849Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}