Error "recursive rendering detected" when rendering media 20+ times

Created on 16 June 2020, over 4 years ago
Updated 12 September 2024, 2 months ago

This has been split off from 🐛 Can only intentionally re-render an entity with references 20 times Needs work .

Drupal\media\Plugin\Filter\MediaEmbed::renderMedia() has a built in stack overflow protection that is intended to prevent infinited recursion when rendering media that references itself. It works by keeping track of a static counter and aborting rendering when the counter reaches 20.

Unfortunately this prevents legitimate use cases that need media to be rendered 20+ times from working correctly. Here is an example use case (adapted from original report by @KarenS in #2940605-21: Can only intentionally re-render an entity with references 20 times ):

My use case is sending a message with images out in email. The email is queued and run on cron which runs as the anonymous user. The images are media entities embedded in the body field. The first 20 recipients get mail with images, everyone else has missing images (and I have dozens of log messages, one for each missing image).

In 🐛 Can only intentionally re-render an entity with references 20 times Needs work an approach is being explorer to keep track of the actual path taken by the recursion instead of just increasing a counter. When the recursion path loops over the same entity 20x we probably are dealing with infinite recursion and can abort rendering.

🐛 Bug report
Status

Postponed

Version

11.0 🔥

Component
Media 

Last updated about 3 hours ago

Created by

🇧🇬Bulgaria pfrenssen Sofia

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇺🇸United States bakulahluwalia Houston

    Any Drupal 10 compatible patch for this issue? #9 patch is failing after D10 upgrade.

  • 🇺🇸United States kevinquillen

    Yes the patch no longer applies in Drupal 10.

  • 🇪🇪Estonia mikkmiggur

    I just did a re-write to the D9 version of the patch so it will apply to the D10.
    No changes in functionality.

  • 🇺🇸United States jvogt Seattle, WA

    I was having the issue when rendering referenced media entities with a view as well. To fix that, I had to make the following changes in /core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php as well. Basically replicating the changes #16 makes to MediaEmbed.php. Sorry it's not a real patch; I couldn't re-roll the D10 patch because I had to apply it manually due to conflicts with another patch.

    diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php
    index cc5a68cb7..f101046f0 100644
    --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php
    +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php
    @@ -2,6 +2,7 @@
     
     namespace Drupal\Core\Field\Plugin\Field\FieldFormatter;
     
    +use Drupal\Core\Config\ConfigFactory;
     use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
     use Drupal\Core\Entity\EntityTypeManagerInterface;
     use Drupal\Core\Field\FieldDefinitionInterface;
    @@ -64,6 +65,13 @@ class EntityReferenceEntityFormatter extends EntityReferenceFormatterBase {
        */
       protected static $recursiveRenderDepth = [];
     
    +  /**
    +   * The config factory.
    +   *
    +   * @var \Drupal\Core\Config\ConfigFactory
    +   */
    +  protected $configFactory;
    +
       /**
        * Constructs an EntityReferenceEntityFormatter instance.
        *
    @@ -87,12 +95,15 @@ class EntityReferenceEntityFormatter extends EntityReferenceFormatterBase {
        *   The entity type manager.
        * @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository
        *   The entity display repository.
    +   * @param \Drupal\Core\Config\ConfigFactory $config_factory
    +   *    The config factory.
        */
    -  public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, LoggerChannelFactoryInterface $logger_factory, EntityTypeManagerInterface $entity_type_manager, EntityDisplayRepositoryInterface $entity_display_repository) {
    +  public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, LoggerChannelFactoryInterface $logger_factory, EntityTypeManagerInterface $entity_type_manager, EntityDisplayRepositoryInterface $entity_display_repository, ConfigFactory $config_factory) {
         parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings);
         $this->loggerFactory = $logger_factory;
         $this->entityTypeManager = $entity_type_manager;
         $this->entityDisplayRepository = $entity_display_repository;
    +    $this->configFactory = $config_factory;
       }
     
       /**
    @@ -109,7 +120,8 @@ public static function create(ContainerInterface $container, array $configuratio
           $configuration['third_party_settings'],
           $container->get('logger.factory'),
           $container->get('entity_type.manager'),
    -      $container->get('entity_display.repository')
    +      $container->get('entity_display.repository'),
    +      $container->get('config.factory')
         );
       }
     
    @@ -174,14 +186,24 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
             . $entity->id();
     
           if (isset(static::$recursiveRenderDepth[$recursive_render_id])) {
    -        static::$recursiveRenderDepth[$recursive_render_id]++;
    +        static::$recursiveRenderDepth[$recursive_render_id]['depth']++;
           }
           else {
    -        static::$recursiveRenderDepth[$recursive_render_id] = 1;
    +        static::$recursiveRenderDepth[$recursive_render_id]['depth'] = 1;
    +      }
    +
    +      // Issue #3151977: get the recursive max depth from media settings,
    +      // if not set, we are defaulting it to 20.
    +      $recursive_render_depth = $this->configFactory->get('media.settings')->get('recursive_render_depth');
    +
    +      // Issue #3151977: if there is no recursive depth in settings, set it to the
    +      // default value of 20.
    +      if ($recursive_render_depth == NULL) {
    +        $recursive_render_depth = 20;
           }
     
           // Protect ourselves from recursive rendering.
    -      if (static::$recursiveRenderDepth[$recursive_render_id] > static::RECURSIVE_RENDER_LIMIT) {
    +      if (static::$recursiveRenderDepth[$recursive_render_id]['depth'] > $recursive_render_depth) {
             $this->loggerFactory->get('entity')->error('Recursive rendering detected when rendering entity %entity_type: %entity_id, using the %field_name field on the %parent_entity_type:%parent_bundle %parent_entity_id entity. Aborting rendering.', [
               '%entity_type' => $entity->getEntityTypeId(),
               '%entity_id' => $entity->id(),
    
  • Thank you for sharing the patches. I would like to combine the solutions from both https://www.drupal.org/project/drupal/issues/3151977#comment-15227120 🐛 Error "recursive rendering detected" when rendering media 20+ times Postponed (#16) and https://www.drupal.org/project/drupal/issues/3151977#comment-15365448 🐛 Error "recursive rendering detected" when rendering media 20+ times Postponed (#17) for testing since both seem to address the issues in my case.

  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MariaDB 10.3.22
    last update 10 months ago
    Patch Failed to Apply
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7 updated deps
    last update 10 months ago
    Patch Failed to Apply
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.2 & sqlite-3.34
    last update 10 months ago
    Patch Failed to Apply
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.2 & pgsql-14.1
    last update 10 months ago
    Patch Failed to Apply
  • 🇵🇭Philippines _renify_ cebu

    I encounter issue during updating security update to 10.1.8 and works when updating to 10.2.2 with patch https://www.drupal.org/files/issues/2024-01-19/core-can-only-intentional...
    https://www.drupal.org/project/drupal/issues/2940605 🐛 Can only intentionally re-render an entity with references 20 times Needs work

  • last update 9 months ago
    Patch Failed to Apply
  • 🇩🇪Germany Anybody Porta Westfalica

    Just ran into this when indexing rendered content using search_api (indexing nodes with media entities): #2913931: Recursive rendering detected when rendering entity

  • 🇯🇴Jordan abu-zakham

    Re-rolled patch #16 for 10.2.x

  • 🇪🇸Spain pcambra Asturies
  • Hitting this issue on my site. Testing Patch in comment #21, i see the field has been added but adjusting the field does not save and reverts back to 20 on pressing 'save configuration'.

    On drupal 10.2.5

  • 🇨🇦Canada lindsay.wils

    I can confirm the same issue as stated in #24 on drupal 10.3.3

  • 🇺🇸United States jvogt Seattle, WA

    It looks like the fact that it's not saving probably has to do with the new way of setting values in config forms. See issue: 📌 Introduce a new #config_target Form API property to make it super simple to use validation constraints on simple config forms, and adopt it in several core config forms Fixed .

    So, in MediaSettingsForm.php replace:

    '#default_value' => $this->config('media.settings')->get('recursive_render_depth') ?? 20,

    with:

    '#config_target' => 'media.settings:standalone_url',

    I just discovered this and don't know how to set a default value in the form if the config value is unset or null, but this should be fine because the patch sets a default in MediaEmbed.php if the config value is null.

  • 🇺🇸United States jvogt Seattle, WA

    recursive_render_depth may also need to be added to media.settings.yml and media.schema.yml.

  • 🇩🇪Germany 4kant

    With patch #21 and the advice from #26 to replace the line after the patch the errors are gone for me.
    I have a fullcalendar view with nodes where media files are referenced.
    Thanks so far!

  • 🇺🇸United States SocialNicheGuru

    Does the patch in #21 need to be updated with the line from #26?

  • First commit to issue fork.
  • 🇺🇸United States jastraat

    This is re-rolled against Drupal 11. It includes the original patch plus the change mentioned in #26 along with the schema file update for the new setting and an additional update to EntityReferenceEntityFormatter. (please disregard the patch above)

  • Pipeline finished with Failed
    about 1 month ago
    Total: 96s
    #306618
  • The Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

    This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

    Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

  • Pipeline finished with Failed
    about 1 month ago
    Total: 754s
    #306770
  • 🇺🇸United States smustgrave

    Have not reviewed but issue summary is missing standard template, if that could be added please.

  • 🇺🇸United States vetchneons

    We're experiencing the same issue with the EntityEmbedFilter. It looks like the problem can also occur in EntityReferenceRevisionsEntityFormatter. I can create an MR to account for these classes.

Production build 0.71.5 2024