We are running Drupal 8.8.5. I can see duplicate aliases when I look at /admin/config/search/path.

Unfortunately, there are many duplicate aliases on our website with 6000 URLs. The /node/1 node has three translations: en, es, and zh-hans. /node/1 also has a second entry for es containing a duplicate path alias which I would like to delete.

I need to find a way to programmatically delete path aliases. If I have Create, Read, Update and Delete (CRUD) operations on the path/alias/langcode, I can create a solution to eliminate the duplicates.

The following code obtains the alias data associated with the node whose ID is equal to 1 and dumps the Path, Alias and LangCode.

$alias = \Drupal::entityTypeManager()->getStorage('path_alias')->load('1');

The base language of the website is English, and the last var_dump() yields en. So far so good.

How can I gain access to the alias data for these two languages? I know the following works.

$alias_es = \Drupal::service('path_alias.manager')->getAliasByPath('/node/1','es');

I need to delete the duplicate Spanish path alias to accomplish my goal, so I need to figure out how to use entities which have a delete() method. You might think the following code should work.

$alias_es = $alias->getTranslation('es');

It returns:

InvalidArgumentException: Invalid translation language (es) specified.

I also tried $alias->getTranslationLanguages(), which returns an array with only one element (['en'] => object(Drupal\Core\Language\Language)).

It appears that our original $alias = \Drupal::entityTypeManager()->getStorage('path_alias')->load('1'); only has one language translation which is English.

How can I gain access to the path aliases for es and zh-hans?

2 Answers 2


How can I gain access to the path aliases for es and zh-hans?

To get all path alias by language for instance es:

$path_alias_manager = \Drupal::entityTypeManager()->getStorage('path_alias');
// Load all path alias for this node for es language.
$alias_objects = $path_alias_manager->loadByProperties([
  'path' => '/node/' . $nid,
  'langcode' => 'en'

I need to delete the duplicate Spanish path alias

$path_alias_manager = \Drupal::entityTypeManager()->getStorage('path_alias');
// Load all path alias for this node for es language.
$alias_objects = $path_alias_manager->loadByProperties([
  'path'     => '/node/' . $nid,
  'langcode' => 'es',

// Get the actual associated spanish path alias to your node.
$spanish_associated_alias = \Drupal::service('path.alias_manager')->getAliasByPath('/node/' . $nid, 'es');
foreach ($alias_objects as $alias_object) {
  // If its not the actual alias delete it.
  if ($alias_object->get('alias')->value !== $spanish_associated_alias ){

Thank you @berramou!

There were two cases to deal with in my situation: (1) an alias that does not match the current alias for a language and (2) a duplicate alias for the same language that matches the current alias. The following code identifies both of these case. The code does not delete the offending alias objects. Please look at your case first and see if the code works for you before removing the commented alias object delete.

$path_alias_manager = \Drupal::entityTypeManager()->getStorage('path_alias');

$nids = \Drupal::entityQuery('node')

$n = 0;
foreach($nids as $nid) {

  $alias_objects = $path_alias_manager->loadByProperties([
    'path' => "/node/$nid",

  foreach(['en','es','zh-hans'] as $lang)
    $current_alias[$lang] = \Drupal::service('path_alias.manager')->getAliasByPath("/node/$nid",$lang);

  $aliases = [];
  foreach($alias_objects as $ao) {
    $lang = $ao->language()->getId();
    $alias = $ao->getAlias();
    $path = $ao->getpath();
    if($current_alias[$lang] != $alias) {
      delete_ao($ao,$alias_objects,$current_alias[$lang],'not current');
    } else {
      if( isset($aliases[$lang]) ) {
      } else {
        $aliases[$lang] = $alias;
  if($n++ == 100)exit;

function delete_ao($ao,$alias_objects,$current,$why) {
  $lang = $ao->language()->getId();
  print ">> delete as $why: ";
  if($why == 'not current')
    print ">> current_alias for $lang: $current\n";
  print "\n";
  // $ao->delete();

function print_ao($ao) {
  print $ao->getPath() . ', ' .
        $ao->getAlias() . ', ' .
        $ao->language()->getId() . "\n";
function print_aos($alias_objects) {
  foreach($alias_objects as $ao)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.