twigphp/Twig · error · SyntaxError
Calling the "parent" function outside of a block is…
Error message
Calling the "parent" function outside of a block is forbidden.
What it means
CoreExtension::parseParentFunction handles the `parent()` call during template compilation. The `parent()` function is only meaningful inside a `{% block %}`; Twig's parser enforces this by peeking at the block stack and throwing a SyntaxError (compile time, not runtime) when the call appears outside any block. Throwing at parse time gives a precise template line and source context.
Solutions
- Move the `{{ parent() }}` call inside a `{% block name %}...{% endblock %}` definition.
- If no parent rendering is intended, remove the parent() call entirely.
- When reusing block-like markup, use `{% block %}` overrides in a template that extends another, rather than parent() in shared partials.
- Re-read the SyntaxError's line/source context to find the misplaced call and relocate it.
Example fix
// before (Twig)
{{ parent() }}
{% block content %}...{% endblock %}
// after
{% block content %}
{{ parent() }}
...
{% endblock %} Defensive patterns
Strategy: validation
Validate before calling
// CI lint step (Symfony) // php bin/console lint:twig templates/ --format=github // fails the build on 'Calling the "parent" function outside of a block' before deploy
Try / catch
try {
$twig->parse($twig->tokenize(new \Twig\Source($templateCode, $name)));
} catch (\Twig\Error\SyntaxError $e) {
if (str_contains($e->getMessage(), 'outside of a block is forbidden')) {
// report template + line for the developer to fix
} else { throw $e; }
} Prevention
- Always place {{ parent() }} inside a {% block %} body, never at top level or in macros
- Lint all templates in CI (lint:twig) to catch misplacement at build time
- When extracting markup out of blocks, search for and relocate any parent() calls
- Use {% use %} imports deliberately; remember imported blocks still need their own inheritance context
When it happens
Trigger: Writing `{{ parent() }}` (or `{{ parent() }}`-style calls) at template top level, inside a macro, inside a `{% set %}` or `{% filter %}` outside of any block definition — anywhere `$parser->peekBlockStack()` returns null. Note `{% block %}` must still be open: parent() must be lexically inside the block body.
Common situations: Copy-pasting `{{ parent() }}` from a child block into a top-level include or macro; moving code out of a block during a refactor and forgetting the parent() call; using parent() inside an embedded template's include rather than its own block override.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Calling the "parent" function on a template that does not…
- A template that extends another one cannot include content…
- You cannot assign a value to
- Cannot use "extend" in a block.
- Cannot use "extend" in a macro.
AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13).
Data as JSON: /api/errors/41f99bfa650411b4.
Report an issue: GitHub.
Appendix: source
Thrown at src/Extension/CoreExtension.php:2224
}
} catch (\Throwable $e) {
while (ob_get_level() > $level) {
ob_end_clean();
}
throw $e;
}
return ob_get_clean();
}
/**
* @internal
*/
public static function parseParentFunction(Parser $parser, Node $fakeNode, $args, int $line): AbstractExpression
{
if (!$blockName = $parser->peekBlockStack()) {
throw new SyntaxError('Calling the "parent" function outside of a block is forbidden.', $line, $parser->getStream()->getSourceContext());
}
if (!$parser->hasInheritance()) {
throw new SyntaxError('Calling the "parent" function on a template that does not call "extends" or "use" is forbidden.', $line, $parser->getStream()->getSourceContext());
}
return new ParentExpression($blockName, $line);
}
/**
* @internal
*/
public static function parseBlockFunction(Parser $parser, Node $fakeNode, $args, int $line): AbstractExpression
{
$fakeFunction = new TwigFunction('block', static fn ($name, $template = null) => null);
$args = (new CallableArgumentsExtractor($fakeNode, $fakeFunction))->extractArguments($args);
return new BlockReferenceExpression($args[0], $args[1] ?? null, $line);View on GitHub (pinned to a414c3a491)