Problem/Motivation
When a FeedsTarget plugin cannot be found for some reason, an import crashes with the following error:
Call to a member function getPluginId() on null in Drupal\feeds\Entity\FeedType->getTargetPlugin()
The mapping page also crashes, with the following error:
Error: Call to a member function hasProperty() on null in Drupal\feeds\Form\MappingForm->buildRow()
Steps to reproduce
Method 1:
- Create a feed type and configure mappings.
- Export the config.
- In the exported config, change one of the target names into a non-existent target.
Example, change title into non_existent:mappings: - target: title map: value: titlemappings: - target: non_existent map: value: title - Import the config.
- Go to the mapping page.
Method 2:
- Create a feed type and configure mappings.
- Remove one of the used FeedsTarget plugins.
- Go to the mapping page.
Proposed resolution
In FeedType::getTargetPlugin(), throw an exception when a target plugin is not found. The exception message should say which target is not found.
Additionally, to prevent the mapping page from crashing, the mapping form should catch that exception.
A functional test is needed that would do the following:
- Add a feed type with a fake target.
- Assert that the mapping page still loads correctly.
- Assert that an import fails gracefully.
- Ensure the mapping for the fake target can be deleted on the mapping page.
Remaining tasks
- Throw an exception in
FeedType::getTargetPlugin() - Catch this exception in MappingForm.
- Add a functional test (see proposed resolution for details).
User interface changes
The mapping page and the import no longer crashes when a FeedsTarget plugin is not found.
API changes
None.
Data model changes
None.
Original report by turpentyne
I'm doing a couple CSV import test runs on a local basic install of Drupal 8.5.3, with php 7.1.12.
I get this error, if I create a new test import:
An AJAX HTTP error occurred.
HTTP Result Code: 200
Debugging information follows.
Path: /batch?id=39&op=do_nojs&op=do
StatusText: OK
ResponseText:
Steps that get me to the error:
I have a CSV file with 16 basic text fields, one having html.
I create a feed type. Settings are: Upload -> CSV --> Node --> testct --> as often as possible.
I map 12 of the fields in CSV file, one set to full html.
I go to content, click feeds and create a new import. Everything works. 200 entries added.
I saw an html character I didn't want - it rendered literal (& #44;). I replaced it with \, in the CSV.
I created a new feed import (just to have clarity of different attempts), and this, is when the error popped up. Import failure.
I deleted all the nodes that the previous import created and tried again. The error appeared again.
I went back to content/feeds and deleted all the feed imports there, and then created a new one. This time, it worked.
| Comment | File | Size | Author |
|---|---|---|---|
| #22 | feeds-missing-target-failure-fix-2969617-22.patch | 2.71 KB | megachriz |
Comments
Comment #2
turpentyne commentedComment #3
megachrizHi, thanks for filing a bug report with details!
The AJAX error is quite general (although it looks strange that the code is '200' which means that the request was successful).
Can you check the logs for more details about the error and report these here?
Comment #4
turpentyne commentedhah! Of course, now I'm having trouble regenerating the error. So I had to go back to when the error happened. I hope this is the right log:
Error: Call to a member function getPluginId() on null in Drupal\feeds\Entity\FeedType->getTargetPlugin() (line 400 of /Users/username/Sites/devdesktop/csmigrate6/modules/feeds/src/Entity/FeedType.php) #0 /Users/username/Sites/devdesktop/csmigrate6/modules/feeds/src/Feeds/Processor/EntityProcessorBase.php(812): Drupal\feeds\Entity\FeedType->getTargetPlugin(3) #1 /Users/username/Sites/devdesktop/csmigrate6/modules/feeds/src/Feeds/Processor/EntityProcessorBase.php(151): Drupal\feeds\Feeds\Processor\EntityProcessorBase->map(Object(Drupal\feeds\Entity\Feed), Object(Drupal\node\Entity\Node), Object(Drupal\feeds\Feeds\Item\DynamicItem)) #2 /Users/username/Sites/devdesktop/csmigrate6/modules/feeds/src/EventSubscriber/LazySubscriber.php(94): Drupal\feeds\Feeds\Processor\EntityProcessorBase->process(Object(Drupal\feeds\Entity\Feed), Object(Drupal\feeds\Feeds\Item\DynamicItem), Object(Drupal\feeds\State)) #3 [internal function]: Drupal\feeds\EventSubscriber\LazySubscriber->Drupal\feeds\EventSubscriber\{closure}(Object(Drupal\feeds\Event\ProcessEvent), 'feeds.process', Object(Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher)) #4 /Users/username/Sites/devdesktop/csmigrate6/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(111): call_user_func(Object(Closure), Object(Drupal\feeds\Event\ProcessEvent), 'feeds.process', Object(Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher)) #5 /Users/username/Sites/devdesktop/csmigrate6/modules/feeds/src/Event/EventDispatcherTrait.php(37): Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch('feeds.process', Object(Drupal\feeds\Event\ProcessEvent)) #6 /Users/username/Sites/devdesktop/csmigrate6/modules/feeds/src/Plugin/QueueWorker/FeedRefresh.php(194): Drupal\feeds\Plugin\QueueWorker\FeedQueueWorkerBase->dispatchEvent('feeds.process', Object(Drupal\feeds\Event\ProcessEvent)) #7 /Users/username/Sites/devdesktop/csmigrate6/modules/feeds/src/Plugin/QueueWorker/FeedRefresh.php(93): Drupal\feeds\Plugin\QueueWorker\FeedRefresh->doProcess(Object(Drupal\feeds\Entity\Feed), Object(Drupal\feeds\Feeds\Item\DynamicItem)) #8 /Users/username/Sites/devdesktop/csmigrate6/core/lib/Drupal/Core/Cron.php(179): Drupal\feeds\Plugin\QueueWorker\FeedRefresh->processItem(Array) #9 /Users/username/Sites/devdesktop/csmigrate6/core/lib/Drupal/Core/Cron.php(144): Drupal\Core\Cron->processQueues() #10 /Users/username/Sites/devdesktop/csmigrate6/core/lib/Drupal/Core/ProxyClass/Cron.php(75): Drupal\Core\Cron->run() #11 /Users/username/Sites/devdesktop/csmigrate6/core/modules/automated_cron/src/EventSubscriber/AutomatedCron.php(65): Drupal\Core\ProxyClass\Cron->run() #12 [internal function]: Drupal\automated_cron\EventSubscriber\AutomatedCron->onTerminate(Object(Symfony\Component\HttpKernel\Event\PostResponseEvent), 'kernel.terminat...', Object(Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher)) #13 /Users/username/Sites/devdesktop/csmigrate6/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(111): call_user_func(Array, Object(Symfony\Component\HttpKernel\Event\PostResponseEvent), 'kernel.terminat...', Object(Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher)) #14 /Users/username/Sites/devdesktop/csmigrate6/vendor/symfony/http-kernel/HttpKernel.php(88): Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch('kernel.terminat...', Object(Symfony\Component\HttpKernel\Event\PostResponseEvent)) #15 /Users/username/Sites/devdesktop/csmigrate6/vendor/stack/builder/src/Stack/StackedHttpKernel.php(32): Symfony\Component\HttpKernel\HttpKernel->terminate(Object(Symfony\Component\HttpFoundation\Request), Object(Drupal\Core\Render\HtmlResponse)) #16 /Users/username/Sites/devdesktop/csmigrate6/core/lib/Drupal/Core/DrupalKernel.php(642): Stack\StackedHttpKernel->terminate(Object(Symfony\Component\HttpFoundation\Request), Object(Drupal\Core\Render\HtmlResponse)) #17 /Users/username/Sites/devdesktop/csmigrate6/index.php(22): Drupal\Core\DrupalKernel->terminate(Object(Symfony\Component\HttpFoundation\Request), Object(Drupal\Core\Render\HtmlResponse)) #18 {main}.
Comment #5
megachrizCall to a member function getPluginId() on null in Drupal\feeds\Entity\FeedType->getTargetPlugin()suggests that a configured target plugin could no longer be found. But that the error no longer comes back suggests that the target plugin that was missing is now found again. Unfortunately, the error doesn't tell us which target plugin was missing for a short time, so that makes it very hard to debug. It could perhaps have been an issue with caching. You are sure you didn't install/uninstall modules in between? Or moved around files from a module? Do you have or had modules installed that extend Feeds?Either way, it would be good if the code checks that the target plugin exists and then throw a more specific error when it doesn't.
Comment #6
turpentyne commentedI bet you're right that it was a caching issue. The last plugin I removed was yesterday - Devel was causing errors with Feeds and several other import options. But nothing today.
Thank you!
Comment #7
megachrizThanks for reporting back. Re-titling this issue.
What errors did Devel cause with Feeds? I remember I did encounter an error as well when trying to print the variables of a feed type with Kint. That could be the same issue.
Comment #8
turpentyne commentedYeah, I think it is the same thing. But, if I remember right, It might've thrown the same errors even with Kint disabled.
I'd posted in the Support area about it, before realizing what it was:
https://www.drupal.org/forum/support/post-installation/2018-05-03/4-recu...
Comment #9
anybodyI agree with #5. That would make sense and help for better debugging. I've just run into "Error: Call to a member function getPluginId() on null". In my case a field had been deleted in the target entity type in the meantime.
The further problem is that the mapping can not be changed anymore due to a different error: admin/structure/feeds/manage/dguard_import_merchants/mapping so that the missing field can not be removed from the feeds mapping.
I solved that by adding the following lines in src/Form/MappingForm.php, Line 158:
which works and seems to be a practicable solution.
Comment #10
anybodyPatch solving the problem with deleted targets described in #9 attached. This doesn't add enhanced error messages for other problems, but in this case makes the mapping usable again and removed the deleted field.
Comment #11
megachrizHm, I don't like that the function is messing with the mapping. We can't be certain that the cause of not finding the target plugin is always gonna be missing a field. It could also be caused by a weird caching issue where somehow a target plugin is not being indexed. Or you when you are working on a target plugin and decide to rename it. Or when you accidentally moved around folders.
Note that the deleted field issue is most likely fixed in dev. With the latest dev version, when you save a feed type, dependencies on fields are calculated and saved on the feed type. This means that when you delete a field, you can see that it will affect a feed type and if you decide to continue deleting the field, Feeds automatically updates the mapping. See #2854914: Deleted Target Field Throws Fatal Error. Come to think of it, all feed types do need to be resaved after updating the Feeds module in order to save these dependency calculations on each feed type. I should be create a follow-up issue to resave all feed types in a database update.
I think throwing an exception is the right thing to do here. To avoid causing a fatal error on the mapping page, the mapping form should catch that exception. It would also be useful to add a functional test here. The test could programmatically add a fake target and then assert that the mapping page still loads correctly. Additionally, the test would try to delete the mapping for the fake target so we can also ensure that an user can clean up.
Would you like to work on that @Anybody? I'd like to make a new release of Feeds next week (or the week after) and I have a few things that are near ready that I like to have finished as well for that release. It would be nice if this thing could then make it too, but not sure if I'll have enough time to get to it.
Comment #12
anybodyHi MegaChriz,
I completely agree with #11. Currently I don't have the time to care for that, sorry. I guess you also don't. So it would be nice if someone may pick this up.
Thank you all so far!
Comment #13
paulgranted commentedI was still experiencing this issue:
MegaChriz's point about re-saving each item is spot on:
Come to think of it, all feed types do need to be resaved after updating the Feeds module in order to save these dependency calculations on each feed type. I should be create a follow-up issue to resave all feed types in a database update.
I had problems with a couple of feeds with the mappings of some fields being missing. Updating these and then resaving allowed the update to complete.
Comment #14
megachriz@paulgranted
Resaving all feed types was in fact included as a database update since 8.x-3.0-alpha2.
Comment #15
megachrizTagging issue for Global Contrib Weekend Event at SFDUG. Thursday Jan 23.
Also updated issue summary.
Comment #16
megachrizI ran into this error while working on #2989279: Add a target to entity ID and then switching branches (on the Feeds git repo).
This patch prevents the fatal error in the following way:
See the image for how this looks like in the UI:

Comment #17
anybodyThank you @MegaChriz, I'll review that soon! :)
Comment #19
anybodySorry, finally I was able to review and test this. It works great! :) Wonderful work once again, you are wonderful.
RTBC!
Comment #21
megachriz@Anybody
Thank you very much for your review and your positive words. :)
Committed #16
Comment #22
megachrizHm, recent changes introduced new failures, apparently.
Patch to fix issues.
Comment #24
megachrizCommitted #22.
Comment #25
anybodyGreat work, thank you very very much @MegaChriz!