Integrity constraint violation errors during migration

Created on 15 November 2019, about 5 years ago
Updated 8 March 2024, 9 months ago

Using the redirect migration template to migrate redirects from D7 to D8, I had a lot of integrity constraint violation errors (duplicate entry hash).

I checked why and apparently these errors occurred when the source database contained multiple records with the same path (usually because one was enabled and the rest was "status: 0").

D8 redirects no longer have a status field, so these multiple D7 redirects (with the same path) could maybe be distilled to a single D8 redirect.

A possible solution (or at least improvement) might be to only migrate enabled redirects.

🐛 Bug report
Status

Needs work

Version

1.0

Component

Code

Created by

🇧🇪Belgium chewi3

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇧🇪Belgium dieterholvoet Brussels

    I had the same issue when the target site had the same redirect as the source site, but without being migrated. It already existed before the migration. Adding the following event subscriber to a custom module fixed the issue for me, not sure if it's abstract enough to include in the module though:

    
    namespace Drupal\redirect\EventSubscriber;
    
    use Drupal\migrate\Event\MigrateEvents;
    use Drupal\migrate\Event\MigratePreRowSaveEvent;
    use Drupal\migrate\MigrateException;
    use Drupal\migrate\Plugin\MigrateIdMapInterface;
    use Drupal\redirect\RedirectRepository;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    
    class DuplicateRedirectMigrateSubscriber implements EventSubscriberInterface
    {
        public function __construct(
            protected RedirectRepository $redirectRepository,
        ) {
        }
    
        public static function getSubscribedEvents(): array
        {
            $events[MigrateEvents::PRE_ROW_SAVE][] = ['onPreRowSave'];
    
            return $events;
        }
    
        public function onPreRowSave(MigratePreRowSaveEvent $event): void
        {
            $migration = $event->getMigration();
            $destination = $migration->getDestinationPlugin();
    
            if ($destination->getPluginId() !== 'entity:redirect') {
                return;
            }
    
            $row = $event->getRow();
            $source = $row->getDestinationProperty('redirect_source');
            $language = $row->getDestinationProperty('language');
            $existingRedirect = $this->redirectRepository->findMatchingRedirect($source['path'], $source['query'] ?? [], $language);
    
            // Skip this row if the redirect already exists outside the migration.
            if ($existingRedirect && !$migration->getIdMap()->getRowByDestination(['rid' => $existingRedirect->id()])) {
                $sourcePath = $source['path'];
                if (isset($source['query'])) {
                    $sourcePath .= '?' . http_build_query($source['query']);
                }
    
                throw new MigrateException(
                    message: sprintf('Redirect already exists for path "%s"', $sourcePath),
                    status: MigrateIdMapInterface::STATUS_IGNORED,
                );
            }
        }
    }
    
Production build 0.71.5 2024