Problem/Motivation

When sending an email in the context of a JSON:API request the response is the error:The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early. Returned object class: Drupal\jsonapi\ResourceResponse.

Steps to reproduce

Any email sent in the context of JSON:API request trows that error. Example:

function bloom_custom_node_insert(\Drupal\Core\Entity\EntityInterface $entity) {

  if ($entity->bundle() === 'match') {
    $match = $entity;
    $ad_1 = $match->field_ad_1->entity;
    // Send email on match
    /** @var \Drupal\easy_email\Service\EmailHandlerInterface $email_handler */
    $email_handler = \Drupal::service('easy_email.handler');

    // Ad_1
    $email_1 = $email_handler->createEmail([
      'type' => 'new_match',
    ]);
    $email_1->setCreatorId($ad_1->getOwner()->id());
    $email_1->setRecipientIds([$ad_1->getOwner()->id()]);
    $status = $email_handler->sendEmail($email_1);

  }
}
CommentFileSizeAuthor
#5 3205673-5.patch607 bytesintrofini

Issue fork easy_email-3205673

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

introfini created an issue. See original summary.

introfini’s picture

I traced the problem to this line $this->tokenEvaluator->evaluateTokens($email) in easy_email/src/Service/EmailHandler.php but couldn't find more than that. So it's something related to token processing since there's a lot of rendering taking place there.

Has a quick fix (inspired by this article) if I wrap the email sending inside this, it works:

$context = new RenderContext();
/* @var \Drupal\Core\Cache\CacheableDependencyInterface $result */
$result = \Drupal::service('renderer')->executeInRenderContext($context, function() {
  // do_things() triggers the code that we don't don't control that in turn triggers early rendering.

(...)

  return  $email_handler->sendEmail($email);

});
// Handle any bubbled cacheability metadata.
if (!$context->isEmpty()) {
  $bubbleable_metadata = $context->pop();
  BubbleableMetadata::createFromObject($result)
    ->merge($bubbleable_metadata);
}

introfini’s picture

Title: JSON:API request gives throws error "leaked metadata was detected" » JSON:API request throws error "leaked metadata was detected"

This fixes the issue:

    $this->renderer->executeInRenderContext(new RenderContext(), function () use ($email) {
      return $this->tokenEvaluator->evaluateTokens($email);
    });

Do you think it's a valid solution?

introfini’s picture

Status: Active » Needs review
StatusFileSize
new607 bytes

Here's the patch...

  • zengenuity committed e4a2b9b on 8.x-1.x authored by introfini
    Issue #3205673 by introfini: JSON:API request throws error "leaked...

  • zengenuity committed 10bd259 on 2.0.x authored by introfini
    Issue #3205673 by introfini: JSON:API request throws error "leaked...
zengenuity’s picture

Looks good to me. I had to do the same thing for the body text field previously.

I committed this to 8.x-1.x and 2.0.x.

One thing though, that I noticed after I committed, was that we are also calling $this->tokenEvaluator->evaluateTokens($email); in the preview function. Since you're getting this error on your site, can you check if preview is working on that template for a similar set of input field values? It seems like it should have the same problem, but I can't easily test it since I did not have the original problem.

zengenuity’s picture

Status: Needs review » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.