{"record":{"id":"851ee6a06fcde7db","repo":"getgrav/grav","slug":"expected-endblock-for-block-s-but-s-given","errorCode":null,"errorMessage":"Expected endblock for block \"%s\" (but \"%s\" given).","messagePattern":"Expected endblock for block \"(.+?)\" \\(but \"(.+?)\" given\\)\\.","errorType":"exception","errorClass":"Twig\\Error\\SyntaxError","httpStatus":null,"severity":"error","filePath":"system/src/Twig/DeferredExtension/DeferredTokenParser.php","lineNumber":52,"sourceCode":"        $deferred = $stream->nextIf(Token::NAME_TYPE, 'deferred');\n\n        if ($deferred) {\n            $block = new DeferredBlockNode($name, new EmptyNode(), $lineno);\n        } else {\n            $block = new BlockNode($name, new EmptyNode(), $lineno);\n        }\n\n        $this->parser->setBlock($name, $block);\n        $this->parser->pushLocalScope();\n        $this->parser->pushBlockStack($name);\n\n        if ($stream->nextIf(Token::BLOCK_END_TYPE)) {\n            $body = $this->parser->subparse([$this, 'decideBlockEnd'], true);\n            if ($token = $stream->nextIf(Token::NAME_TYPE)) {\n                $value = $token->getValue();\n\n                if ($value != $name) {\n                    throw new SyntaxError(\\sprintf('Expected endblock for block \"%s\" (but \"%s\" given).', $name, $value), $stream->getCurrent()->getLine(), $stream->getSourceContext());\n                }\n            }\n        } else {\n            $body = new Nodes([\n                new PrintNode($this->parser->parseExpression(), $lineno),\n            ]);\n        }\n        $stream->expect(Token::BLOCK_END_TYPE);\n\n        $block->setNode('body', $body);\n        $this->parser->popBlockStack();\n        $this->parser->popLocalScope();\n\n        return new BlockReferenceNode($name, $lineno, $this->getTag());\n    }\n\n    public function decideBlockEnd(Token $token): bool\n    {","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Twig/DeferredExtension/DeferredTokenParser.php#L34-L70","documentation":"Grav's bundled Twig deferred extension supplies the block token parser used here. After parsing a block body, it accepts an optional name after {% endblock %} and verifies that it matches the opening block name; a mismatch raises Twig SyntaxError with both names and the source line.","triggerScenarios":"Render a template containing {% block hero %}...{% endblock old_hero %}. The parser reaches DeferredTokenParser.php:48-53, sees endblock's name differs from hero, and throws before the template can compile.","commonSituations":"Copying and renaming a block but forgetting its endblock, merge conflicts that pair mismatched tags, nested block editing, and generated templates whose names are interpolated incorrectly.","solutions":["Change the name after {% endblock %} to exactly match the opening block.","Remove the optional name and use plain {% endblock %}, which this parser accepts.","Search the whole template chain, includes, and embedded strings for both names reported in the message.","Run twig lint or compile templates in CI after large template refactors."],"exampleFix":"// before\n{% block hero %}\n  <h1>{{ page.title }}</h1>\n{% endblock intro %}\n\n// after\n{% block hero %}\n  <h1>{{ page.title }}</h1>\n{% endblock hero %}\n{# or simply: {% endblock %} #}","handlingStrategy":"validation","validationCode":"$source = file_get_contents($templateFile);\npreg_match_all('/{%\\s*(block|endblock)\\b([^%}]*)%}/', $source, $matches, PREG_SET_ORDER);\n$stack = [];\nforeach ($matches as $tag) {\n    if ($tag[1] === 'block') {\n        preg_match('/([A-Za-z_]\\w*)/', $tag[2], $name);\n        $stack[] = $name[1] ?? null;\n    } elseif ($stack) {\n        preg_match('/([A-Za-z_]\\w*)/', $tag[2], $name);\n        $expected = array_pop($stack);\n        if (($name[1] ?? $expected) !== $expected) {\n            throw new InvalidArgumentException(\"endblock name does not match block {$expected}\");\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    $twig->load($templateName);\n} catch (SyntaxError $e) {\n    return ['error' => 'Template syntax error: ' . $e->getMessage(), 'line' => $e->getLine()];\n}","preventionTips":["Run twig lint on templates in CI.","Rename opening and closing tags together.","Prefer unnamed {% endblock %} when names add no value.","Review template merges for changed block names.","Compile page templates after bulk find-and-replace operations."],"tags":["twig","template-syntax","deferred-extension","block","grav"],"backgroundTag":"template-block-name-mismatch","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}