Nodes being rendered too early?

Created on 11 February 2019, almost 6 years ago
Updated 8 February 2023, almost 2 years ago

I have a custom entity type, "task", which has an entity reference field to a content type (nodes) "project".

I'm using a progressively-decoupled setup. Listing tasks using views and using jsonAPI have both always worked fine.

I recently implemented node_grants, and simply declaring the hook (even without returning anything) breaks my ability to query tasks using jsonAPI.

The error message is the dreaded:
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\jsonapi\ResourceResponse. in Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext() (line 154 of /var/www/dev-1/XX/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php).

The custom entity type is fairly vanilla - it was originally set up using Drupal Console. And this breaks even without fully implementing node_grants; declaring it is enough to break it.

I've spent a long time digging into this and the only way I've been able to get around the issue is deleting the (premature?) rendering of nodes:

diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 9fdabf32b4..dcda495519 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
function node_query_node_access_alter(AlterableInterface $query) {
   $request = \Drupal::requestStack()->getCurrentRequest();
   $renderer = \Drupal::service('renderer');
   if ($request->isMethodCacheable() && $renderer->hasRenderContext()) {
     $build = ['#cache' => ['contexts' => ['user.node_grants:' . $op]]];
-    $renderer->render($build);
   }
 }

I know that's a security risk because it prevents cache tags from bubbling up / risk of users seeing each other's data / bypassing access.

What I would *like* to do, but can't find a way to is something like this:

diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 9fdabf32b4..dcda495519 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -1119,8 +1119,9 @@ function node_query_node_access_alter(AlterableInterface $query) {
   $request = \Drupal::requestStack()->getCurrentRequest();
   $renderer = \Drupal::service('renderer');
   if ($request->isMethodCacheable() && $renderer->hasRenderContext()) {
+    $render_context = $renderer->getCurrentRenderContext();
     $build = ['#cache' => ['contexts' => ['user.node_grants:' . $op]]];
-    $renderer->render($build);
+    $render_context->update($build);
   }
 }

That isn't possible because getCurrentRenderContext is a private method.

Am I totally off-base here? Any other solution? Like I said, everything works perfectly fine until I create a *literally empty* (or even properly populated) node_grants function. If I rename that function to something else (so that I am not using node_grants anymore), all of the tasks load fine.

-----
EDIT/UPDATE: See the attached patch "3032041-node_grant_premature_render-2.patch" for an updated potential solution which the above led me to.

I now believe the issue is with Renderer::hasRenderContext() returning true even if the context returns a count of 0.

πŸ› Bug report
Status

Needs work

Version

10.1 ✨

Component
Node systemΒ  β†’

Last updated 3 days ago

No maintainer
Created by

πŸ‡ΊπŸ‡ΈUnited States ashrafabed

Live updates comments and jobs are added and updated live.
  • Needs tests

    The change is currently missing an automated test that fails when run with the original code, and succeeds when the bug has been fixed.

Sign in to follow issues

Comments & Activities

Not all content is available!

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

Production build 0.71.5 2024