Magento 2 : URL key For Specified Store Already Exists

We have a Magento 2 multisite setup, with categories set up.

When editing some (but not all) of these categories, in different store views, Magento throws following error and does not save data:

In this case, the name of the “Supplements” category was edited in Chinese store view. It shows changing the value of name in this view but the refreshing page shows that it is not saved at all.

Editing same category in default store view does not result in the same issue.

Ensuring that the “Default” checkbox is unchecked for the URL key field in the Chinese store view makes no difference

We have tried removing URL rewrites for this category (based on the error message and other posts we have reviewed) but this does not help.

We are running M2 Community 2.1.5.

Traced the issue back to a db save error in the url rewrite table:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '90-3' for key 'URL_REWRITE_REQUEST_PATH_STORE_ID', query was: INSERT INTO `url_rewrite` (`redirect_type`,`is_autogenerated`,`metadata`,`description`,`store_id`,`entity_type`,`entity_id`,`request_path`,`target_path`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?)

So multiple entries are saved into the rewrite table in one go (possibly corresponding to the subcats AND their associated products under the given category.

If I track that particular value back to the URLs that are being saved I have this entry in the array”

[167] => Array
(
[redirect_type] => 0
[is_autogenerated] => 1
[description] =>
[entity_type] => product
[entity_id] => 15
[request_path] => 90-3
[target_path] => catalog/product/view/id/15
[store_id] => 3
)

I can’t see any request paths with “90-3” in it. There are target paths with “catalog/product/view/id/15” but only for default and nz site. I’ve tried deleting these but that didn’t help.

I've fixed this issue. And I have 2 solutions for that.

The first one: Clean up your database in table url_rewrite (Change the url_key of all category). You can write UpgradeData script for this solution.

The second one: Remove the duplication data when saving category. This data is throw in method doReplace(\$urls) in \vendor\magento\module-url-rewrite\Model\Storage\DbStorage.php file.

protected function doReplace(\$urls)
{
foreach (\$this->createFilterDataBasedOnUrls(\$urls) as \$type => \$urlData) {
\$urlData[UrlRewrite::ENTITY_TYPE] = \$type;
\$this->deleteByData(\$urlData);
}
\$data = [];
foreach (\$urls as \$url) {
\$data[] = \$url->toArray();
}
\$this->insertMultiple(\$data);
}

After debugging, I found out \$data variable has a duplicate record. If you want this method to work without any errors. Rewrite this method above to:

protected function doReplace(\$urls)
{
foreach (\$this->createFilterDataBasedOnUrls(\$urls) as \$type => \$urlData) {
\$urlData[UrlRewrite::ENTITY_TYPE] = \$type;
\$this->deleteByData(\$urlData);
}
\$data = [];
\$storeId_requestPaths = [];
foreach (\$urls as \$url) {
\$storeId = \$url->getStoreId();
\$requestPath = \$url->getRequestPath();
// Skip if is exist in the database
\$sql = "SELECT * FROM url_rewrite where store_id = \$storeId and request_path = '\$requestPath'";
\$exists = \$this->connection->fetchOne(\$sql);

if (\$exists) continue;

\$storeId_requestPaths[] = \$storeId . '-' . \$requestPath;
\$data[] = \$url->toArray();
}

// Remove duplication data;
\$n = count(\$storeId_requestPaths);
for (\$i = 0; \$i < \$n - 1; \$i++) {
for (\$j = \$i + 1; \$j < \$n; \$j++) {
if (\$storeId_requestPaths[\$i] == \$storeId_requestPaths[\$j]) {
unset(\$data[\$j]);
}
}
}
\$this->insertMultiple(\$data);
}

If you want to get more details. Please, read my comment in

https://github.com/magento/magento2/issues/7298

• this solution not work for me its give erorr Something went wrong while saving the category. – Jigs Parmar Mar 15 '18 at 7:02
• @jigsparmar sorry for the late response, in your case it might be some other bugs. You should debug to the save category function and see what is causing the problem. – Toan Tam Mar 21 '18 at 1:53
• I added that code but when I save category, it gives error: Something went wrong while saving the category. – Kishan Patadia Apr 12 '18 at 9:16
• I think it is another bugs. Not url key problem. In your case, you should at the log and check if there is any exception. – Toan Tam Apr 13 '18 at 4:14
• The solution worked for me but it's now possible to have to categories with the same URL and I suppose it's not intended – SimoneB May 13 '19 at 11:12

This is an acknowledged bug from Magento 2. Here is a workaround for it, I assume you already know how to create plugin/preference of Magento 2.

module-catalog-url-rewrite/Model/Product/AnchorUrlRewriteGenerator.php (L58)

/**
* Generate list based on categories
*
* @param int \$storeId
* @param Product \$product
* @param ObjectRegistry \$productCategories
* @return UrlRewrite[]
*/
public function generate(\$storeId, Product \$product, ObjectRegistry \$productCategories)
{
\$urls = [];
foreach (\$productCategories->getList() as \$category) {
\$anchorCategoryIds = \$category->getAnchorsAbove();
if (\$anchorCategoryIds) {
foreach (\$anchorCategoryIds as \$anchorCategoryId) {
//Default: \$anchorCategory = \$this->categoryRepository->get(\$anchorCategoryId);
\$anchorCategory = \$this->categoryRepository->get(\$anchorCategoryId, \$storeId);
\$urls[] = \$this->urlRewriteFactory->create()
->setEntityType(ProductUrlRewriteGenerator::ENTITY_TYPE)
->setEntityId(\$product->getId())
->setRequestPath(
\$this->urlPathGenerator->getUrlPathWithSuffix(
\$product,
\$storeId,
\$anchorCategory
)
)
->setTargetPath(
\$this->urlPathGenerator->getCanonicalUrlPath(
\$product,
\$anchorCategory
)
)
->setStoreId(\$storeId)
}
}
}

return \$urls;
}

module-catalog-url-rewrite/Model/ProductUrlRewriteGenerator.php (L146)

/**
* Generate list of urls for global scope
*
* @param \Magento\Framework\Data\Collection \$productCategories
*
* @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[]
*/
protected function generateForGlobalScope(\$productCategories)
{
\$urls = [];
\$productId = \$this->product->getEntityId();
foreach (\$this->product->getStoreIds() as \$id) {
if (!\$this->isGlobalScope(\$id)
&& !\$this->storeViewService->doesEntityHaveOverriddenUrlKeyForStore(\$id, \$productId, Product::ENTITY)
) {
// Default: \$urls = array_merge(\$urls, \$this->generateForSpecificStoreView(\$id, \$productCategories));

// before loading the category collection by looping it, clone it and set the correct store id,
// so we get the correct url_path & url_key for that specific store id
\$storeSpecificProductCategories = clone \$productCategories;
\$storeSpecificProductCategories->setStoreId(\$id);

\$urls = array_merge(\$urls, \$this->generateForSpecificStoreView(\$id, \$storeSpecificProductCategories));
}
}
return \$urls;
}

Hope this helps.

• when i should have to use Before or After or around event? – Pramod Kharade Feb 22 '18 at 13:57
• not work for me – Jigs Parmar Mar 15 '18 at 7:00

90-3 means URL key 90 for store_id 3. You must look for two entries which have URL key 90. And generally, the issue is caused by URL key of a product under that category. You could also go to catalog product entity varchar table and search for the product which has URL key of 90. I guess 119 is the attribute id for URL key. Change URL key of that product

I was also facing the same issue while adding/editing categories.

Firstly I found there was wrong attribute id in "catalog_category_entity_varchar" table for url_key and url_path. Then I checked the exact attribute_id of both attributes ('url_key' and 'url_path').

e.g in "catalog_category_entity_varchar" table it was showing '117' and '118' but exact id was '119' and '120'. Then I found there was some rows in "catalog_category_entity_varchar" table with these (correct id '119','120').

I followed below steps to resolve the issue.

• firstly I searched rows in "catalog_category_entity_varchar" where attribute id is in (117,118) and exported the data from the table.
• then I searched rows in "catalog_category_entity_varchar" where attribute id is in (117,118,119,120) and deleted these data (rows) from table.
• then I just opened the exported file in Notepad++, and changed attribute ids 117 with 119 and 118 with 120 and imported the data again.

Make sure take the backup of the database before doing above steps.

After a week digging the only thing that worked for me was https://www.safemage.com/url-optimization-after-migration-magento-2.html It is a paid module - \$69. The support responds if you have questions. The bad thing is that you must keep the plugin forever or until the bug is fixed by Magento team... I had to downgrade to 2.2.7 to use it. It says it works on 2.3 but it does not. Here is a quote from the link:

Migration from Magento 1 to Magento 2 often leads to a problem to save some categories on the backend. There appears this unavoidable error “URL key for specified store already exists”. Our team has thoroughly investigated the problem and come to a conclusion there is no unified and reliable solution to thrash out the problem. Even if you managed to remove all duplicated URLs, the error would surface again after another "Save" procedure.

After looking for internet for days i can't find exact solution of this. Then i found if we change the URLKEY of the category it will not show this error so i have done this.

\$category->setPath(\$parentCategory->getPath())
->setParentId(\$parentId)
->setName('test1')
->setIsActive(true)
->setUrlKey(rand(1,1000000000));

\$category->save();

I use random function to add category in database with random no using ->setUrlKey(rand(1,1000000000)); you can add any thing in this like duplicate category name with some random no etc. and errors gone if it helps you give an UP. thanks

Just trying truncating url_rewrite table and run re-indexing. It will create all url-key's automatically.

Note: Please take back up of table before truncating.

• It will not recreate them automatically. Magento has removed that functionality. – Adad64 Sep 5 '18 at 16:05