EasyCorp / EasyCorp/EasyAdminBundle

Infinite recursion in content.html.twig when a custom page extends it without overriding content_title/page_title

Open Beginner friendly
#7,633 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
PHP
Stars
4.3k
Forks
1.1k
Avg merge
8d 2h
Merged PRs (30d)
11

Description

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_titlecontent_titlepage_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_titlecontent_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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with @EasyAdmin/page/content.html.twig and the page_title evaluation in layout.html.twig, then reproduce the issue with a custom dashboard template that overrides neither title block. Confirm the change stops recursion while preserving the documented title-block workaround and lets the dashboard render with empty content.

Written by the indexing model from the issue text.

Assessment

Tech stack
php, symfony
Domain
backend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.