{"record":{"id":"deb2be73808002ba","repo":"twigphp/Twig","slug":"unexpected-end-of-template","errorCode":null,"errorMessage":"Unexpected end of template.","messagePattern":"Unexpected end of template\\.","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"src/TokenStream.php","lineNumber":53,"sourceCode":"    }\n\n    public function __toString(): string\n    {\n        return implode(\"\\n\", $this->tokens);\n    }\n\n    public function injectTokens(array $tokens): void\n    {\n        $this->tokens = array_merge(\\array_slice($this->tokens, 0, $this->current), $tokens, \\array_slice($this->tokens, $this->current));\n    }\n\n    /**\n     * Sets the pointer to the next token and returns the old one.\n     */\n    public function next(): Token\n    {\n        if (!isset($this->tokens[++$this->current])) {\n            throw new SyntaxError('Unexpected end of template.', $this->tokens[$this->current - 1]->getLine(), $this->source);\n        }\n\n        return $this->tokens[$this->current - 1];\n    }\n\n    /**\n     * Tests a token, sets the pointer to the next one and returns it or throws a syntax error.\n     *\n     * @return Token|null The next token if the condition is true, null otherwise\n     */\n    public function nextIf($primary, $secondary = null)\n    {\n        return $this->tokens[$this->current]->test($primary, $secondary) ? $this->next() : null;\n    }\n\n    /**\n     * Tests a token and returns it or throws a syntax error.\n     */","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/twigphp/Twig/blob/a414c3a491defb5a60f2fc88ef79ff37c90010cd/src/TokenStream.php#L35-L71","documentation":"TokenStream::next() advances past the last token; when there is no next token, Twig throws 'Unexpected end of template.' This means the template's syntax required more tokens than exist — typically an unclosed construct.","triggerScenarios":"A template ending while the parser still expects tokens: unclosed {% if %}/{% for %}/{% block %}, an unfinished expression like '{{ foo', or a missing {% endtag %}; any parser call to next()/expect() at EOF triggers it.","commonSituations":"Truncated template files from failed deploys/partial saves; copy-pasting template fragments without their closing tags; forgetting {% endif %}, {% endfor %}, or {% endblock %}.","solutions":["Check the reported line (the last parsed line) for an unclosed tag or expression and add the matching end tag","Verify the template file was fully deployed/saved and is not truncated","Run twig-lint (bin/console lint:twig in Symfony) to catch the unclosed construct before deployment"],"exampleFix":"// before\n{% if user %}\n  {{ user.name }}\n// after\n{% if user %}\n  {{ user.name }}\n{% endif %}","handlingStrategy":"try-catch","validationCode":"// Pre-compile templates to catch EOF/unclosed constructs before render\n$env->parse($env->tokenize(new Source($template, $name)));","typeGuard":null,"tryCatchPattern":"try {\n    $html = $twig->render($name, $context);\n} catch (SyntaxError $e) {\n    if (str_contains($e->getMessage(), 'Unexpected end of template')) {\n        // log template name + line; alert that a tag is unclosed or file truncated\n    }\n    throw $e;\n}","preventionTips":["Always close {% if %}/{% for %}/{% block %}/{% macro %} with their end tags","Verify deployed template files match the repository (checksums/CI artifact)","Add twig linting (lint:twig) to CI so truncation and unclosed tags fail the build"],"tags":["twig","syntax-error","template","unclosed-tag"],"backgroundTag":"unexpected-end-of-template","analyzedSha":"a414c3a491defb5a60f2fc88ef79ff37c90010cd","analyzedAt":"2026-09-13T15:10:46.849Z","contentChangedAt":"2026-09-13T15:10:46.849Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}