Problem/Motivation

If you have a route that uses the bundle parameter, and a local task linked to that route, when you visit a node that is not in one of the bundles defined the local task block gets a max-age of 0. This is because ParamConverterManager throws a ParamNotConvertedException if the entity returned is NULL, which AccessManager catches and adds the max-age 0:

      // Uncacheable because conversion of the parameter may not have been
      // possible due to dynamic circumstances.
      $result = AccessResult::forbidden()->setCacheMaxAge(0);
      return $return_as_object ? $result : $result->isAllowed();

LocalTaskManager calls the checkedNamedRoute method of the access manager.

If you enable http.response.debug_cacheability_headers: true the whole page gets a 0 (Uncacheable) warning for x-drupal-cache-max-age response header.

This is mitigated by the fact that the localTasksBlocks returns True for the createPlaceholder method which means it is using a lazy builder by default. So actually the page is cacheable but the header is confusing and it is really hard to track down what is setting the max-age property.

Steps to reproduce

Create a route that uses the bundle option:

my_module.my_route:
  path: /node/{node}/do-something
  defaults:
    _title: 'Do something route'
    _controller: '\Drupal\my_module\Controller\MyController::index'
  requirements:
    _permission: 'administer search_api'
    _entity_access: 'node.update'
  options:
    parameters:
      node:
        type: entity:node
        bundle:
          - product_list_page

Create a local task and assign the route to it:

my_module.my_task:
  route_name: my_module.my_route:
  title: 'Do something task'
  base_route: entity.node.canonical

Set this to true in services.yml

http.response.debug_cacheability_headers: true

Now view any node that is not in the bundle option. The x-drupal-cache-max-age response header will now be: 0 (Uncacheable).

Proposed resolution

I don't know what the best solution is. Either setting max-age to 0 is inappropriate or, since the local tasks use a lazy builder anyway maybe they shouldn't be used in determining if the page is cacheable when it bubbles up?

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

Comments

achap created an issue.