Since Drupal 11.3.0, Renderer::executeInRenderContext() runs code in a Fiber and can pause it so other placeholders render first. Views runs the facet query inside it, so DefaultFacetManager::updateResults() can be paused halfway:
  1. updateResults() clears builtFacets, then starts filling results. The query pauses.
  2. Meanwhile, another facet block builds facet X. It adds URLs to X's results and marks X as built in builtFacets.
  3. The paused fill resumes and replaces X's results with new results that have no URLs.
  4. builtFacets still says X is built, so it isn't rebuilt. The summary reads X's active result, the URL is NULL, and new Link() throws.

I confirmed this with logging: on failing requests, updateResults() ran in four different Fibers.

Steps to reproduce

  1. Drupal 11.3+ (seen on 11.4.9), Facets 2.0.10 (same code in 3.0.7 and 3.0.x), Search API + Views.
  2. On one page, place two or more facet blocks and one facets summary block for the same Views facet source.
  3. Run drush cr, then open the page with two facets active (for example ?facet[0]=a:1&facet[1]=b:2). It works.
  4. Open the page with a different pair of values. You get a 500 error.code>

Proposed resolution:

  1. In DefaultFacetManager::updateResults(), clear builtFacets again after fillFacetsWithResults(), so facets built during the pause are rebuilt.
  2. In DefaultFacetsSummaryManager::build(), check that every active result has a URL, and rebuild any facet that doesn't (up to 3 tries).

Comments

sakshi@17 created an issue.