Problem/Motivation

The new core EntityLinks filter (core/modules/filter/src/Plugin/Filter/EntityLinks.php) catches exceptions thrown while resolving a linked entity and tries to log them:

catch (\Exception $e) {
  Error::logException('filter', $e);
}

However, Drupal\Core\Utility\Error::logException()requires a Psr\Log\LoggerInterfaceas its first argument:
public static function logException(LoggerInterface $logger, \Throwable $exception, ...): void
So instead of logging the original (recoverable) exception, the catch block itself throws a fatal:

TypeError: Drupal\Core\Utility\Error::logException(): Argument #1 ($logger)
must be of type Psr\Log\LoggerInterface, string given, called in
core/modules/filter/src/Plugin/Filter/EntityLinks.php on line 101

Because this happens during text rendering, it aborts whatever was rendering the content — in our case it broke the Search API re-indexing batch (HTTP 500 on /batch), but it can break any page render that runs the filter over content whose data-entity-type / data-entity-uuid attributes can't be resolved (e.g. malformed markup such as data-entity-type="true"). The bug effectively defeats the try/catch whose entire purpose is to make the filter resilient.
This code was introduced very recently (commit 5417f19c, 2025-11-20, for issue #3317769 "Add support for linking to entities in CKEditor 5") and the buggy line is still present on 11.x.

Steps to reproduce

On a site with the EntityLinks filter enabled in a text format, create content containing an anchor with a data-entity-type / data-entity-uuid that cannot be resolved to a real entity (e.g. x).
2. Render that content (view the node, or trigger a Search API / rendered-item index batch over it).
3. Observe the request fail with HTTP 500 and the TypeError above instead of the intended logged warning.

Proposed resolution

Pass a real logger to Error::logException(). Minimal one-line change:

catch (\Exception $e) {
  Error::logException(\Drupal::logger('filter'), $e);
}

(Or, preferably for testability, inject LoggerChannelFactoryInterface / a 'filter' logger channel into the plugin via dependency injection and use that instead of the static \Drupal::logger() call.)

Remaining tasks

• Decide between the minimal `\Drupal::logger('filter')` fix and proper DI of a logger channel into the filter plugin.
• Add a test (kernel/unit) asserting that an unresolvable entity link is logged and the filter returns the original markup instead of throwing.
• Review/MR + commit to 11.x (and backport to supported stable branches that contain the EntityLinks filter).

User interface changes

None.

Introduced terminology

None.

API changes

None. (The fix only corrects an incorrect call to an existing API; no signatures change.)

Data model changes

None.

Release notes snippet

Fixed a fatal TypeError in the EntityLinks filter that occurred when a linked entity could not be resolved: the filter now correctly logs the underlying exception to the filter channel and continues, instead of crashing the render/page request.

Issue fork drupal-3607178

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

remco hoeneveld created an issue. See original summary.

remco hoeneveld’s picture

Issue summary: View changes
cilefen’s picture

Status: Active » Needs work
Issue tags: +Needs merge request

remco hoeneveld’s picture

Status: Needs work » Needs review
smustgrave’s picture

Version: 11.3.x-dev » main
Status: Needs review » Needs work
Issue tags: -Needs merge request +Needs tests

Fixes need to land in main first and would see if there’s a test that could be expanded that shows the bug

remco hoeneveld’s picture

@smustgrave good pointers. I have added tests, I have added a version for 11.3 and main, and can confirm that this shows what goes wrong. Again, it's not rocket science what happens, the problem is that Error::logException() needs LoggerInterface $logger, and now a string was passed to it, so when an error occurs, it crashes.

remco hoeneveld’s picture

Status: Needs work » Needs review
smustgrave’s picture

Status: Needs review » Needs work

Can actually see on the main branch this failed phpstan. Which is good and means we could probably drop the test on main.

Baseline needs to be updated but are there other instances of this error that may be quick fixes?

dcam’s picture

Component: link.module » filter.module

Moving to the correct component.