Hello,

I'm trying to create a page with xml output (a special kind of xml sitemap). But I can't figure out how to make it cacheable and adding a cache tag, when I try this, an error is thrown.

My controller just provides a build function returning a response object, the data is provided as string.

Uncached version works fine, sending the page:

public function build() {

    // Fetch the sitemap contents (just a string containing xml)
    $output = $this->getSitemap();

    // Create the response
    $response = new Response($output, Response::HTTP_OK, array('content-type' => 'application/xml'));
    return $response;

}

Now, I'm trying to provide a cacheable response:

public function build() {

    // Fetch the sitemap contents (just a string containing xml)
    $output = $this->getSitemap();

    // Create the response, adding appropriate cacheability metadata
    $response = new CacheableResponse($output, Response::HTTP_OK, array('content-type' => 'application/xml'));
    $response->getCacheableMetadata()->addCacheTags(array('my_cache_tag'));
    return $response;

  }

This throws an error complaining about leaked metadata and early rendering:

The website encountered an unexpected error. Please try again later.

LogicException: 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\Core\Cache\CacheableResponse. in Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext() (line 154 of core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php).

Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
call_user_func_array(Object, Array) (Line: 139)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 62)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 98)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 77)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 50)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 628)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

The code however seems to work for short output strings.

Am I doing something wrong?

Thanks, and best regards,
Boris

Comments

drubb created an issue. See original summary.

drubb’s picture

Issue summary: View changes
nicxvan’s picture

Version: 8.1.1 » 8.2.x-dev
Category: Support request » Bug report
Priority: Normal » Major

I am having a similar issue.

I am trying to generate a cacheableJsonResponse and I get an exception
LogicException: 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\Core\Cache\CacheableJsonResponse. in Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext() (line 154 of /var/www/development/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php).

After fairly extensive review, it seems that the issue occurs when loading a node to generate the response. EFQs and loading taxonomy do not cause the problem.

Further it seems to be a false exception since commenting it out causes all of the expected tags to be generated and the page is cacheable. Changing content expires the cache as expected as well.

For comparison my code to generate the response looks like this:

$cacheMetadata = new CacheableMetadata();
    $cacheMetadata->setCacheContexts([]);
    $cacheMetadata->setCacheMaxAge(3600);
    $cacheMetadata->setCacheTags($cacheTags);

    $response = [
      'filters' => $filters,
      'pages' => $pages,
    ];


    $response = new CacheableJsonResponse($response, 200);
    $response->addCacheableDependency($cacheMetadata);
    return $response;

As mentioned it works as expected if I comment out the exception or remove the node load call when generating the pages variable.

nicxvan’s picture

Title: How to create a cacheable response object? » Generating cacheable responses results in Logic Exception
boesbo’s picture

! I Have same issue... have they news ?

Berdir’s picture

Category: Bug report » Support request
Priority: Major » Normal

You need to debug the cache object there and identify what kind of cacheability metadata is there and where it is coming from. If loading a node causes it for you, then it is possibly a hook_node_load() or similar implementation, could also be file_entity or so although that hould be fixed.

See #2638686: Exception in EarlyRenderingControllerWrapperSubscriber is a DX nightmare, remove it for improving that.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.