Skip to content

Cannot save category containing products linked to root category #7916

Closed
@cykirsch

Description

@cykirsch

Preconditions

  1. Magento 2.1.3 EE

Steps to reproduce

I copied my data from 1.7.0.2 using the provided data migration tool. Afterward, when trying to save a category, I would get the error "Something went wrong while saving the category.". Exception log stack trace:

[2016-12-16 19:54:45] report.CRITICAL: Exception: Notice: Undefined offset: 1 in /srv/www/vendor/magento/module-catalog-url-rewrite/Model/ProductUrlRewriteGenerator.php on line 199 in /srv/www/vendor/magento/framework/App/ErrorHandler.php:61
Stack trace:
#0 /srv/www/vendor/magento/module-catalog-url-rewrite/Model/ProductUrlRewriteGenerator.php(199): Magento\Framework\App\ErrorHandler->handler(8, 'Undefined offse...', '/srv/www/vendor...', 199, Array)
#1 /srv/www/vendor/magento/module-catalog-url-rewrite/Model/ProductUrlRewriteGenerator.php(166): Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator->isCategoryProperForGenerating(Object(Magento\Catalog\Model\Category\Interceptor), '1')
#2 /srv/www/vendor/magento/module-catalog-url-rewrite/Model/ProductUrlRewriteGenerator.php(149): Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator->generateForSpecificStoreView('1', Object(Magento\Catalog\Model\ResourceModel\Category\Collection))
#3 /srv/www/vendor/magento/module-catalog-url-rewrite/Model/ProductUrlRewriteGenerator.php(117): Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator->generateForGlobalScope(Object(Magento\Catalog\Model\ResourceModel\Category\Collection))
#4 /srv/www/vendor/magento/module-catalog-url-rewrite/Observer/UrlRewriteHandler.php(80): Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator->generate(Object(Magento\Catalog\Model\Product\Interceptor))
#5 /srv/www/vendor/magento/module-catalog-url-rewrite/Observer/CategoryProcessUrlRewriteSavingObserver.php(58): Magento\CatalogUrlRewrite\Observer\UrlRewriteHandler->generateProductUrlRewrites(Object(Magento\Catalog\Model\Category\Interceptor))
#6 /srv/www/vendor/magento/framework/Event/Invoker/InvokerDefault.php(73): Magento\CatalogUrlRewrite\Observer\CategoryProcessUrlRewriteSavingObserver->execute(Object(Magento\Framework\Event\Observer))
#7 /srv/www/vendor/magento/framework/Event/Invoker/InvokerDefault.php(61): Magento\Framework\Event\Invoker\InvokerDefault->_callObserverMethod(Object(Magento\CatalogUrlRewrite\Observer\CategoryProcessUrlRewriteSavingObserver), Object(Magento\Framework\Event\Observer))
#8 /srv/www/vendor/magento/module-staging/Model/Event/Manager.php(97): Magento\Framework\Event\Invoker\InvokerDefault->dispatch(Array, Object(Magento\Framework\Event\Observer))
#9 /srv/www/var/generation/Magento/Staging/Model/Event/Manager/Proxy.php(95): Magento\Staging\Model\Event\Manager->dispatch('catalog_categor...', Array)
#10 /srv/www/vendor/magento/framework/Model/AbstractModel.php(802): Magento\Staging\Model\Event\Manager\Proxy->dispatch('catalog_categor...', Array)
#11 /srv/www/vendor/magento/module-catalog/Model/Category.php(1077): Magento\Framework\Model\AbstractModel->afterSave()
#12 /srv/www/var/generation/Magento/Catalog/Model/Category/Interceptor.php(583): Magento\Catalog\Model\Category->afterSave()
#13 /srv/www/vendor/magento/framework/EntityManager/Observer/AfterEntitySave.php(34): Magento\Catalog\Model\Category\Interceptor->afterSave()
#14 /srv/www/vendor/magento/framework/Event/Invoker/InvokerDefault.php(73): Magento\Framework\EntityManager\Observer\AfterEntitySave->execute(Object(Magento\Framework\Event\Observer))
#15 /srv/www/vendor/magento/framework/Event/Invoker/InvokerDefault.php(61): Magento\Framework\Event\Invoker\InvokerDefault->_callObserverMethod(Object(Magento\Framework\EntityManager\Observer\AfterEntitySave), Object(Magento\Framework\Event\Observer))
#16 /srv/www/vendor/magento/module-staging/Model/Event/Manager.php(97): Magento\Framework\Event\Invoker\InvokerDefault->dispatch(Array, Object(Magento\Framework\Event\Observer))
#17 /srv/www/var/generation/Magento/Staging/Model/Event/Manager/Proxy.php(95): Magento\Staging\Model\Event\Manager->dispatch('magento_catalog...', Array)
#18 /srv/www/vendor/magento/framework/EntityManager/EventManager.php(51): Magento\Staging\Model\Event\Manager\Proxy->dispatch('magento_catalog...', Array)
#19 /srv/www/vendor/magento/module-staging/Model/Operation/Update.php(208): Magento\Framework\EntityManager\EventManager->dispatchEntityEvent('Magento\\Catalog...', 'save_after', Array)
#20 /srv/www/vendor/magento/framework/EntityManager/EntityManager.php(87): Magento\Staging\Model\Operation\Update->execute(Object(Magento\Catalog\Model\Category\Interceptor), Array)
#21 /srv/www/vendor/magento/module-catalog/Model/ResourceModel/Category.php(1025): Magento\Framework\EntityManager\EntityManager->save(Object(Magento\Catalog\Model\Category\Interceptor))
#22 /srv/www/vendor/magento/framework/Interception/Interceptor.php(74): Magento\Catalog\Model\ResourceModel\Category->save(Object(Magento\Catalog\Model\Category\Interceptor))
#23 /srv/www/vendor/magento/framework/Interception/Chain/Chain.php(70): Magento\Catalog\Model\ResourceModel\Category\Interceptor->___callParent('save', Array)
#24 /srv/www/vendor/magento/framework/Interception/Chain/Chain.php(63): Magento\Framework\Interception\Chain\Chain->invokeNext('Magento\\Catalog...', 'save', Object(Magento\Catalog\Model\ResourceModel\Category\Interceptor), Array, 'catalogsearchFu...')
#25 /srv/www/vendor/magento/module-catalog-search/Model/Indexer/Fulltext/Plugin/Category.php(43): Magento\Framework\Interception\Chain\Chain->Magento\Framework\Interception\Chain\{closure}(Object(Magento\Catalog\Model\Category\Interceptor))
#26 /srv/www/vendor/magento/module-catalog-search/Model/Indexer/Fulltext/Plugin/Category.php(29): Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Category->addCommitCallback(Object(Magento\Catalog\Model\ResourceModel\Category\Interceptor), Object(Closure), Object(Magento\Catalog\Model\Category\Interceptor))
#27 /srv/www/vendor/magento/framework/Interception/Chain/Chain.php(67): Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Category->aroundSave(Object(Magento\Catalog\Model\ResourceModel\Category\Interceptor), Object(Closure), Object(Magento\Catalog\Model\Category\Interceptor))
#28 /srv/www/vendor/magento/framework/Interception/Interceptor.php(138): Magento\Framework\Interception\Chain\Chain->invokeNext('Magento\\Catalog...', 'save', Object(Magento\Catalog\Model\ResourceModel\Category\Interceptor), Array, 'clean_cache')
#29 /srv/www/vendor/magento/framework/App/Cache/FlushCacheByTags.php(60): Magento\Catalog\Model\ResourceModel\Category\Interceptor->Magento\Framework\Interception\{closure}(Object(Magento\Catalog\Model\Category\Interceptor))
#30 /srv/www/vendor/magento/framework/Interception/Interceptor.php(142): Magento\Framework\App\Cache\FlushCacheByTags->aroundSave(Object(Magento\Catalog\Model\ResourceModel\Category\Interceptor), Object(Closure), Object(Magento\Catalog\Model\Category\Interceptor))
#31 /srv/www/var/generation/Magento/Catalog/Model/ResourceModel/Category/Interceptor.php(364): Magento\Catalog\Model\ResourceModel\Category\Interceptor->___callPlugins('save', Array, Array)
#32 /srv/www/vendor/magento/framework/Model/AbstractModel.php(631): Magento\Catalog\Model\ResourceModel\Category\Interceptor->save(Object(Magento\Catalog\Model\Category\Interceptor))
#33 /srv/www/vendor/magento/framework/Interception/Interceptor.php(146): Magento\Framework\Model\AbstractModel->save()
#34 /srv/www/var/generation/Magento/Catalog/Model/Category/Interceptor.php(1534): Magento\Catalog\Model\Category\Interceptor->___callPlugins('save', Array, Array)
#35 /srv/www/vendor/magento/module-catalog/Controller/Adminhtml/Category/Save.php(203): Magento\Catalog\Model\Category\Interceptor->save()
#36 /srv/www/var/generation/Magento/Catalog/Controller/Adminhtml/Category/Save/Interceptor.php(24): Magento\Catalog\Controller\Adminhtml\Category\Save->execute()
#37 /srv/www/vendor/magento/framework/App/Action/Action.php(102): Magento\Catalog\Controller\Adminhtml\Category\Save\Interceptor->execute()
#38 /srv/www/vendor/magento/module-backend/App/AbstractAction.php(226): Magento\Framework\App\Action\Action->dispatch(Object(Magento\Framework\App\Request\Http))
#39 /srv/www/vendor/magento/framework/Interception/Interceptor.php(74): Magento\Backend\App\AbstractAction->dispatch(Object(Magento\Framework\App\Request\Http))
#40 /srv/www/vendor/magento/framework/Interception/Chain/Chain.php(70): Magento\Catalog\Controller\Adminhtml\Category\Save\Interceptor->___callParent('dispatch', Array)
#41 /srv/www/vendor/magento/framework/Interception/Chain/Chain.php(63): Magento\Framework\Interception\Chain\Chain->invokeNext('Magento\\Catalog...', 'dispatch', Object(Magento\Catalog\Controller\Adminhtml\Category\Save\Interceptor), Array, 'adminAuthentica...')
#42 /srv/www/vendor/magento/module-backend/App/Action/Plugin/Authentication.php(143): Magento\Framework\Interception\Chain\Chain->Magento\Framework\Interception\Chain\{closure}(Object(Magento\Framework\App\Request\Http))
#43 /srv/www/vendor/magento/framework/Interception/Chain/Chain.php(67): Magento\Backend\App\Action\Plugin\Authentication->aroundDispatch(Object(Magento\Catalog\Controller\Adminhtml\Category\Save\Interceptor), Object(Closure), Object(Magento\Framework\App\Request\Http))
#44 /srv/www/vendor/magento/framework/Interception/Chain/Chain.php(63): Magento\Framework\Interception\Chain\Chain->invokeNext('Magento\\Catalog...', 'dispatch', Object(Magento\Catalog\Controller\Adminhtml\Category\Save\Interceptor), Array, 'log')
#45 /srv/www/vendor/magento/module-logging/App/Action/Plugin/Log.php(69): Magento\Framework\Interception\Chain\Chain->Magento\Framework\Interception\Chain\{closure}(Object(Magento\Framework\App\Request\Http))
#46 /srv/www/vendor/magento/framework/Interception/Chain/Chain.php(67): Magento\Logging\App\Action\Plugin\Log->aroundDispatch(Object(Magento\Catalog\Controller\Adminhtml\Category\Save\Interceptor), Object(Closure), Object(Magento\Framework\App\Request\Http))
#47 /srv/www/vendor/magento/framework/Interception/Interceptor.php(138): Magento\Framework\Interception\Chain\Chain->invokeNext('Magento\\Catalog...', 'dispatch', Object(Magento\Catalog\Controller\Adminhtml\Category\Save\Interceptor), Array, 'adminMassaction...')
#48 /srv/www/vendor/magento/module-backend/App/Action/Plugin/MassactionKey.php(33): Magento\Catalog\Controller\Adminhtml\Category\Save\Interceptor->Magento\Framework\Interception\{closure}(Object(Magento\Framework\App\Request\Http))
#49 /srv/www/vendor/magento/framework/Interception/Interceptor.php(142): Magento\Backend\App\Action\Plugin\MassactionKey->aroundDispatch(Object(Magento\Catalog\Controller\Adminhtml\Category\Save\Interceptor), Object(Closure), Object(Magento\Framework\App\Request\Http))
#50 /srv/www/var/generation/Magento/Catalog/Controller/Adminhtml/Category/Save/Interceptor.php(65): Magento\Catalog\Controller\Adminhtml\Category\Save\Interceptor->___callPlugins('dispatch', Array, Array)
#51 /srv/www/vendor/magento/framework/App/FrontController.php(55): Magento\Catalog\Controller\Adminhtml\Category\Save\Interceptor->dispatch(Object(Magento\Framework\App\Request\Http))
#52 /srv/www/vendor/magento/framework/Interception/Interceptor.php(74): Magento\Framework\App\FrontController->dispatch(Object(Magento\Framework\App\Request\Http))
#53 /srv/www/vendor/magento/framework/Interception/Chain/Chain.php(70): Magento\Framework\App\FrontController\Interceptor->___callParent('dispatch', Array)
#54 /srv/www/vendor/magento/framework/Interception/Interceptor.php(138): Magento\Framework\Interception\Chain\Chain->invokeNext('Magento\\Framewo...', 'dispatch', Object(Magento\Framework\App\FrontController\Interceptor), Array, 'install')
#55 /srv/www/vendor/magento/framework/Module/Plugin/DbStatusValidator.php(69): Magento\Framework\App\FrontController\Interceptor->Magento\Framework\Interception\{closure}(Object(Magento\Framework\App\Request\Http))
#56 /srv/www/vendor/magento/framework/Interception/Interceptor.php(142): Magento\Framework\Module\Plugin\DbStatusValidator->aroundDispatch(Object(Magento\Framework\App\FrontController\Interceptor), Object(Closure), Object(Magento\Framework\App\Request\Http))
#57 /srv/www/var/generation/Magento/Framework/App/FrontController/Interceptor.php(26): Magento\Framework\App\FrontController\Interceptor->___callPlugins('dispatch', Array, Array)
#58 /srv/www/vendor/magento/framework/App/Http.php(135): Magento\Framework\App\FrontController\Interceptor->dispatch(Object(Magento\Framework\App\Request\Http))
#59 /srv/www/vendor/magento/framework/App/Bootstrap.php(258): Magento\Framework\App\Http->launch()
#60 /srv/www/pub/index.php(37): Magento\Framework\App\Bootstrap->run(Object(Magento\Framework\App\Http))
#61 {main} [] []

The structure is a bit different (an EE difference I am guessing), but the method with the error is just like this one: https://github.com/magento/magento2/blob/develop/app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php#L166

list(, $rootCategoryId) fails with undefined offset because $category->getParentIds() returns an empty array. It took me quite awhile, but I eventually found the cause. For each product in the category saved, it will call this isCategoryProperForGenerating method for each category that product happens to be in.

It turns out I have several products assigned to the Root Catalog category. No idea why that is, but that's how it was in M1--the very first entry in magento1.catalog_category_product is our first product assigned to category_id 1. $category->getParentId() for this product is 0, so it passes the != TREE_ROOT_ID (AKA 1) check and goes on to the list call, which breaks because the Root Catalog category has no parents. If it also checks != ROOT_CATEGORY_ID (AKA 0), it should work.

Expected result

  1. "You saved the category."

Actual result

  1. "Something went wrong while saving the category."

Suggested solution

In vendor/magento/module-catalog-url-rewrite/Model/ProductUrlRewriteGenerator.php, change line 194 to

        if ($category->getParentId() != \Magento\Catalog\Model\Category::TREE_ROOT_ID
            && $category->getParentId() != \Magento\Catalog\Model\Category::ROOT_CATEGORY_ID
        ) {

But in order to not modify core code myself, I'll just be clearing out the Root Category assignments:

delete from catalog_category_product where category_id = 1;

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue: Ready for WorkGate 4. Acknowledged. Issue is added to backlog and ready for developmentbug report

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions