Description
@EasyAdmin/page/content.html.twig defines two blocks that reference each other with no base case:
{# deprecated 'The "page_title" block is deprecated, use "content_title" instead.' #}
{% block page_title %}{{ block('content_title') }}{% endblock %}
{% block content_title %}{{ block('page_title') }}{% endblock %}
page_title → content_title → page_title → … This is fine for EasyAdmin's own CRUD pages because they always override content_title. But any custom page (e.g. a Dashboard homepage) that extends @EasyAdmin/page/content.html.twig and overrides neither block recurses infinitely the moment the title is rendered — layout.html.twig evaluates page_title to build the <title>:
{% set page_title_block_output %}{% block page_title %}{{ block('content_title') }}{% endblock %}{% endset %}
<title>{{ page_title_block_output|striptags|raw }}</title>
How to reproduce
DashboardController:
#[Route('/admin', name: 'admin')]
public function index(): Response
{
return $this->render('admin/dashboard.html.twig');
}
templates/admin/dashboard.html.twig (overrides neither title block):
{% extends '@EasyAdmin/page/content.html.twig' %}
Open /admin.
Expected
The dashboard renders (empty content is fine).
Actual
Infinite recursion. The exact symptom depends on which PHP limit trips first:
- dev (Symfony profiler on): the Twig profiler instruments every recursion level (
microtime()/memory_get_usage()/new Twig\Profiler\Profile), slowing it down so it hits max_execution_time first:
Fatal error: Maximum execution time of N seconds exceeded
at vendor/twig/twig/src/Extension/ProfilerExtension.php:32
(misleadingly points at the profiler, which is just the innermost frame)
- prod / profiler off: native stack overflow:
Maximum call stack size of 8339456 bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
Confirmed by Xdebug profiling: @EasyAdmin/page/content.html.twig is re-entered ~110k times/9s at flat-ish depth — the mutual block() calls.
Root cause
The page_title ↔ content_title blocks are mutually recursive with no terminating output. Since both are deprecated and kept only for BC, neither provides a real default, so nothing breaks the cycle unless the leaf template overrides one.
Workaround
Override content_title (or page_title) in the custom template:
{% extends '@EasyAdmin/page/content.html.twig' %}
{% block content_title %}Dashboard{% endblock %}
{% block main %}{% endblock %}
Versions
- easycorp/easyadmin-bundle: 4.29.11 (blocks still mutually-referencing on
4.x)
- twig/twig: 3.27.1
- symfony: 5.4
- PHP: 8.4
Description
@EasyAdmin/page/content.html.twigdefines two blocks that reference each other with no base case:page_title→content_title→page_title→ … This is fine for EasyAdmin's own CRUD pages because they always overridecontent_title. But any custom page (e.g. a Dashboard homepage) that extends@EasyAdmin/page/content.html.twigand overrides neither block recurses infinitely the moment the title is rendered —layout.html.twigevaluatespage_titleto build the<title>:{% set page_title_block_output %}{% block page_title %}{{ block('content_title') }}{% endblock %}{% endset %} <title>{{ page_title_block_output|striptags|raw }}</title>How to reproduce
DashboardController:templates/admin/dashboard.html.twig(overrides neither title block):{% extends '@EasyAdmin/page/content.html.twig' %}Open
/admin.Expected
The dashboard renders (empty content is fine).
Actual
Infinite recursion. The exact symptom depends on which PHP limit trips first:
microtime()/memory_get_usage()/new Twig\Profiler\Profile), slowing it down so it hitsmax_execution_timefirst:Confirmed by Xdebug profiling:
@EasyAdmin/page/content.html.twigis re-entered ~110k times/9s at flat-ish depth — the mutualblock()calls.Root cause
The
page_title↔content_titleblocks are mutually recursive with no terminating output. Since both are deprecated and kept only for BC, neither provides a real default, so nothing breaks the cycle unless the leaf template overrides one.Workaround
Override
content_title(orpage_title) in the custom template:{% extends '@EasyAdmin/page/content.html.twig' %} {% block content_title %}Dashboard{% endblock %} {% block main %}{% endblock %}Versions
4.x)