Problem/Motivation

Drupal 11.4 added recursion protection to EntityViewBuilder. Every entity build gets a matched pair of callbacks in EntityViewBuilder::getBuildDefaults():

$build['#pre_render'] = [[$this, 'setRecursiveRenderProtection']];
$build['#post_render'] = [[$this, 'unsetRecursiveRenderProtection']];

LayoutParagraphsBuilder::buildComponent() replaces #post_render instead of appending to it, so core's cleanup callback is dropped:

$build = $view_builder->view($entity, $preview_view_mode, $entity->language()->getId());
$build['#post_render'] = [
  [$this, 'postRenderComponent'],
];

Every component the builder renders therefore adds its recursion key to the static tracker and never removes it. The key survives for the rest of the request, and the next render of that same paragraph is aborted as a false positive:

User warning: Recursive rendering attempt aborted for
paragraph:entity_id:772:11204:fiber_id:194:en:default. In progress: Array ( ... ) in
Drupal\Core\Entity\EntityViewBuilder->setRecursiveRenderProtection() (line 564 of
core/lib/Drupal/Core/Entity/EntityViewBuilder.php).

The aborted build gets #printed = TRUE, so that component renders empty.

Rendering the same paragraph twice in one request is ordinary, not a bug. Any theme whose paragraph.html.twig assigns content|render to a variable - a widespread idiom for bubbling the cacheability of fields the template does not print, and for testing whether content is empty - renders every field and every nested component a second time, because Twig resets #printed on each render.

Steps to reproduce

  1. Drupal 11.4, Layout Paragraphs, a section with at least one child component.
  2. Add {% set rendered_content = content|render %} to the top of the theme's paragraph.html.twig.
  3. Open the host entity's edit form. The nested component renders empty and the warning above is logged.

Proposed resolution

Append the callback rather than replace the array:

$build['#post_render'][] = [$this, 'postRenderComponent'];

Remaining tasks

Review. The same line is in 2.0.x, 2.1.x and 2.2.x and needs the same one-line change.

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

serhii shandaliuk created an issue. See original summary.

serhii shandaliuk’s picture

Status: Active » Needs review

MR !262. One line: $build['#post_render'][] = [$this, 'postRenderComponent']; instead of replacing the array.

Regression test added: a test module whose paragraph.html.twig renders content twice, plus a functional test that puts a text component inside a one-column section and loads the host node's edit form. Without the fix the nested component's second render is aborted and the resulting PHP warning fails the test.

Verified on Drupal 11.4.5, PHP 8.3, Layout Paragraphs 3.0.x:

  • phpunit tests/src/Functional/ - 2 tests, 25 assertions, OK.
  • phpcs --standard=Drupal,DrupalPractice - clean.
  • phpstan - no errors.

Also reproduced and fixed on a live 11.4.5 site running 2.1.3 with Mercury Editor: 12 warnings per page load before, none after.

benstallings’s picture

Status: Needs review » Reviewed & tested by the community

This is a correct, narrowly-scoped fix with a good regression test, and MR!262 matches the resolution proposed in the issue. Nothing to flag as a defect.

justin2pin made their first commit to this issue’s fork.