Some contrib modules will decorate the path.alias_manager service in order to perform custom checks and operations.
Scenario:
For instance, the fixed_path_alias module provides functionality where you can store URL Aliases in config and it will recreate the info in storage when missing.
When used alongside the menu_export module, which also provides a menu link import/export feature, an error will be produced on attempt to import menu items because early in the process, the menu items do not yet exist.
Additional scenario:
The wse_menu contrib module keeps a separate menu tree per workspace. A menu link created in a workspace is still findable by its link.uri, but its menu tree definition is absent from the Live tree. So when _menu_link_content_update_path_alias() runs in Live, it finds the entity by URI and calls updateDefinition() on a plugin ID that doesn't exist.
Error:
The website encountered an unexpected error. Please try again later.</br></br><em class="placeholder">Drupal\Core\Entity\EntityStorageException</em>: Plugin ID 'menu_link_content:3996d408-1d0b-4838-ab65-031ab1cb9826' was not found. in <em class="placeholder">Drupal\Core\Entity\Sql\SqlContentEntityStorage->save()</em> (line <em class="placeholder">847</em> of <em class="placeholder">core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php</em>). <pre class="backtrace">Drupal\Core\Plugin\Factory\ContainerFactory->createInstance('menu_link_content:3996d408-1d0b-4838-ab65-031ab1cb9826', Array) (Line: 233)
Drupal\Core\Menu\MenuLinkManager->createInstance('menu_link_content:3996d408-1d0b-4838-ab65-031ab1cb9826') (Line: 364)
Drupal\Core\Menu\MenuLinkManager->updateDefinition('menu_link_content:3996d408-1d0b-4838-ab65-031ab1cb9826', Array, ) (Line: 73)
_menu_link_content_update_path_alias('/manage-content/courses-and-content-library/courses') (Line: 56)
menu_link_content_path_insert(Array)
call_user_func_array('menu_link_content_path_insert', Array) (Line: 403)
Drupal\Core\Extension\ModuleHandler->invokeAll('path_insert', Array) (Line: 119)
Drupal\Core\Path\AliasStorage->save('/manage-content/course', '/manage-content/courses-and-content-library/courses', 'und') (Line: 209)
Drupal\fixed_path_alias\FixedPathAliasManager->restoreAlias(Array) (Line: 160)
Drupal\fixed_path_alias\FixedPathAliasManager->lookupFixedPath('/manage-content/courses-and-content-library/courses', 'en', 1) (Line: 106)
Drupal\fixed_path_alias\FixedPathAliasManager->getPathByAlias('/manage-content/courses-and-content-library/courses') (Line: 35)
Drupal\Core\PathProcessor\PathProcessorAlias->processInbound('/manage-content/courses-and-content-library/courses', Object) (Line: 70)
Drupal\Core\PathProcessor\PathProcessorManager->processInbound('/manage-content/courses-and-content-library/courses', Object) (Line: 157)
Drupal\Core\Path\PathValidator->getPathAttributes('manage-content/courses-and-content-library/courses', Object, ) (Line: 122)
Drupal\Core\Path\PathValidator->getUrl('manage-content/courses-and-content-library/courses', ) (Line: 89)
Drupal\Core\Path\PathValidator->getUrlIfValidWithoutAccessCheck('manage-content/courses-and-content-library/courses') (Line: 415)
Drupal\Core\Url::fromInternalUri(Array, Array) (Line: 307)
Drupal\Core\Url::fromUri('internal:/manage-content/courses-and-content-library/courses', Array) (Line: 172)
Drupal\link\Plugin\Field\FieldType\LinkItem->getUrl() (Line: 94)
Drupal\menu_link_content\Entity\MenuLinkContent->getUrlObject() (Line: 156)
Drupal\menu_link_content\Entity\MenuLinkContent->getPluginDefinition() (Line: 222)
Drupal\menu_link_content\Entity\MenuLinkContent->postSave(Object, ) (Line: 526)
Drupal\Core\Entity\EntityStorageBase->doPostSave(Object, ) (Line: 720)
Drupal\Core\Entity\ContentEntityStorageBase->doPostSave(Object, ) (Line: 452)
Drupal\Core\Entity\EntityStorageBase->save(Object) (Line: 838)
Drupal\Core\Entity\Sql\SqlContentEntityStorage->save(Object) (Line: 394)
Drupal\Core\Entity\EntityBase->save() (Line: 87)
Drupal\menu_export\Form\MenuImportForm->submitForm(Array, Object)
call_user_func_array(Array, Array) (Line: 111)
Drupal\Core\Form\FormSubmitter->executeSubmitHandlers(Array, Object) (Line: 51)
Drupal\Core\Form\FormSubmitter->doSubmitForm(Array, Object) (Line: 590)
Drupal\Core\Form\FormBuilder->processForm('menu_import_form', Array, Object) (Line: 319)
Drupal\Core\Form\FormBuilder->buildForm('menu_import_form', Object) (Line: 93)
Drupal\Core\Controller\FormController->getContentResult(Object, Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 582)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 151)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 67)
Drupal\simple_oauth\HttpMiddleware\BasicAuthSwap->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 693)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
</pre>
Proposed solution:
Add a call to MenuLinkManager::hasDefinition right before call to MenuLinkManager::updateDefinition in _menu_link_content_update_path_alias()
| Comment | File | Size | Author |
|---|
Issue fork drupal-3072557
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:
- 3072557-11.x
changes, plain diff MR !16022
- 3072557-plugin-id-not-found
changes, plain diff MR !16021
Comments
Comment #2
teknorahComment #5
kristen polPatch still applies to 9.1.x.
Comment #6
kristen polThanks for the issue and patch.
1) The change in the code is clear.
2) Based on issue summary, it's unclear if this can be tested without using custom/contributed code.
3) Kicking off tests in 9.1.x.
Comment #7
kristen polMarking needs work for tests.
Comment #8
larowlanI think the issue here might be cached plugin definitions
I wonder if fixed_path_alias should be clearing cached definitions in the menu link plugin manager before it does its restoreAlias call?
Comment #14
floown commentedHello.
I just add a node and have this message instead to display the node:
I don't know if it's the same problem. Perhaps a related problem: https://www.drupal.org/project/drupal/issues/3056633#comment-14761566
Regards
Comment #20
amateescu commentedI've bumped into the same problem on a project, but from a different angle. In my case, the
wse_menucontrib module keeps a separate menu tree per workspace. A menu link created in a workspace is still findable by itslink.uriin the Live entity storage (its default revision has the URI), but its menu tree definition is absent from the Live tree. So when_menu_link_content_update_path_alias()runs in Live, it finds the entity by URI and callsupdateDefinition()on a plugin ID that doesn't exist.Guarding this against non-existent definitions is correct regardless of how the divergence arises, the import case in the original report, or per-workspace menu trees here. It also mirrors the existence check core already does in
MenuLinkContent::postSave()(getDefinition($id, FALSE)beforeupdateDefinition()), added in #2605684: Routing silently fails in kernel tests.Comment #21
smustgrave commentedWonder if we can cleanup the summary some to include maybe core steps to reproduce? Or are we saying this is only triggered by contrib and being defensive?
Comment #22
amateescu commentedI don't have any steps to reproduce with core alone, but I tried to explain in detail what can happen with a contrib module that provides parallel menu trees. So.. yes, this is about being defensive and consistent with
MenuLinkContent::postSave().Comment #23
smustgrave commentedThat case looks like good defensive step. And thanks for commenting why it's needed.
Comment #26
catchThis looks OK. Not usually a fan of defensiveness but it seems like there are real cases where this is unavoidable.
Committed/pushed to main, 11.x and 11.4.x, thanks!