Drupal version: 8.5.0
Feeds version: 8.x-3.x-dev (2018-03-11)
PHP version: 7.0.22
Hi, first of all: thanks for your hard work on the feeds module!
Problem:
AJAX error (server error 500) + fatal error in webserver error log during first feed import after feed creation. Vanilla Drupal 8.5.0, trying to import into Article CT.
Steps to recreate:
- install vanilla D8.5.0
- install feeds 8.x-3.x-dev via composer
- create new feed type 'blog item', leave all options default ('download', 'rss/atom', 'node', 'article')
- add new feed, url: https://dri.es/rss.xml (tried various other feeds too, with same result)
--> batch job starts, error message is shown:
An AJAX HTTP error occurred.
HTTP Result Code: 500
Debugging information follows.
Path: /batch?id=6&op=do_nojs&op=do
StatusText: Internal Server Error
ResponseText:
The following gets written to the webserver's error log:
[error] 31600#31600: *128 FastCGI sent in stderr: "PHP message: PHP Fatal error: Method Drupal\Component\Render\FormattableMarkup::__toString() must not throw an exception, caught Drupal\feeds\Exception\ValidationException: in /path/to/vhost/www/modules/contrib/feeds/src/Feeds/Processor/EntityProcessorBase.php on line 469
Thanks.
| Comment | File | Size | Author |
|---|---|---|---|
| #28 | feeds-validation-exception-formattable-markup-2951965-28.patch | 5.84 KB | megachriz |
| #22 | feeds-formattable-markup-fatal-error-2951965-22-D8.patch | 1.52 KB | wolffereast |
Comments
Comment #2
megachrizDid you add any mappings? On the Feed type edit form there is a tab called 'Mapping'. (At some point I would like to add a button called "Save and add mapping" on the feed type add form, so you go directly to mapping after creating a feed type.)
Anyway, if you did *not* add any mappings, I think Feeds should warn you when creating a feed.
Comment #3
jpoesen commentedI did add mappings - sorry to have left that out of the steps to recreate.
I tried with a few simple mappings (title and content), and I tried without any mappings. Both result in the same error.
Comment #4
publishing future commentedI run into the same problem when importing a csv-file with mapping for title as unique field.
Comment #5
megachrizIt sounds like that there was a validation error and reporting that validation error resulted into another error.
In order to help, I will need details about your configuration plus a sample of the feed you are importing (@jpoesen already provided a sample source file). Can you provide the following:
Comment #6
mikran commentedHere is feature module, and test file that reproduces the bug is
feeds/tests/resources/csv/content.csvAnd steps to reproduce
and this happens when I want to import additional data to existing entities - but I do not want to create new entities if existing entity is not found.
Comment #7
hongpong commentedThanks for all your work on feeds. I had similar errors - wrote up a huge issue thread stepping through what I was doing and then d.o logged me out and I lost it last night.
I think that some things are treated as required when they are not required in the content type / field level . It should just skip the cell/field instance instead of trying to populate from an empty cell.
If I try to use http addresses to populate the filefields/imagefields it is quite finicky. Typos in urls will produce 500 php errors instead of continuing to the next cell.
I would suggest making it easier to put feeds into a debug mode that dumps more information like the $url value and major values from the CSV row like title, into the logger, so it is easier to find bad data. Also somehow getting exception information into the logger would help people.
In my case I confirmed when trying to import image files and/or vcf text files . the src/Feeds/Target/File.php: getFileName($url) function gets called when there is no file name, eg when a cell is empty. So the test is actually 'false' value is compared to $this->fileExtensions . Then it throws exception. This may be more prone to happen on the last node / csv row, it seemed like when i cut off my csv file to only a couple rows it would still throw errrors.
On mine this is line 190 but normally is line 188 - i tried dumping some vars in the process but it didn't work. (they are commented out right now)
This is the exception: throw new TargetValidationException('The file, %url, failed to save because the extension, %ext, is invalid.', ['%url' => $url, '%ext' => $extension]);
It was called from getFile - line 156: $filepath = $destination . '/' . $this->getFileName($value);
I will post more as I can determine it. Thank you!
Comment #8
megachriz@mikran
I tried to reproduce the bug reported in this issue with your feature module. The import did not succeed indeed, but I did not get a fatal error. Only a message that field_debug should not be empty. This happened after adding a feed and clicking on "Save and import". Did you initiate an import in a other way to trigger the fatal error?
That an import does not complete because of missing values for a field you did not map to is indeed annoying, but it is Drupal's way of saying "I do not accept any entity that is missing a value for a required field". Personally, I think Feeds should indeed skip validation for fields that you don't map to, but on the other hand Drupal has a point that it should not allow invalid data. An entity in the database where a required field is empty is invalid. It is an issue in the D7 version of Feeds as well: #2918840: Field validation errors in item: only validate mapped fields. In that issue I posted a patch to limit the validation to only mapped fields.
@HongPong
Your issue with empty values for file targets sounds a lot like #2772595: When mapping to File or Image fields, empty source for target_id causes Exception and breaks import process.. Is it the same or is your issue different?
We should definitely catch errors in case of a typo in an URL.
Logging failed imports is on my wishlist too. I was thinking such logging feature could be modeled after the commerce_log module (part of the Commerce project). At least one thing I think we should aim for when developing that feature is that the logs can be written to something else as the database. That was a feature request in the D7 version of Feeds: #1367044: Use syslog.module for feeds_log and/or an option to disable log. There is already an issue open about adding a logging feature for D8: #2907721: Log items that failed to import.
Comment #9
hongpong commented@MegaChriz Yeah I think my error is similar but I got similar errors from both vcf text files and images. So I think we need to look carefully at File.php. If I have some luck with Xdebug I'll try to nail this down more & possibly file a separate issue if it is truly different than these.
Comment #10
mikran commented@MegaChriz
Ok, I figured it out what we're doing differently. PHP 5.6.33 throws this error, PHP 7.0.29 does not.
jpoesen reported PHP version as 7.0.22 that produced this error, so is it something between PHP 7.0.22 and 7.0.29 that changes this?
Comment #11
wolffereast commentedI'm running php version 5.6.30 and am also seeing this issue. From what I can tell, using the FormattableMarkup object as the message causes PHP to think that it is the FormattableMarkup object throwing an error, which isn't allowed. Forcing it to a string fixes the error for me. Not sure if having a string stored as the message messes with anything else.
My STR are similar.
Fresh install of D8. Enabled feeds. Created an article feed type, added mappings to title and image. Ran the feed against a test CSV and had an error that triggered the exception on line 188 of File.php. That was triggering the fatal error.
Edit: I can feature the feed if need be
Comment #12
hongpong commentedwolffereast It appears that this prevents the fatal error! I had much better luck getting my import with images through successfully. There is still curl errors thrown on non existent files. (as if curl was invoked with no target url I believe). What excellent timing thank you.
Comment #13
mikran commentedComment #14
mikran commentedComment #15
hongpong commentedfwiw my errors have been happening with PHP 7.1.14 as well. I haven't tried 5.6 on this.
Comment #16
wolffereast commented@HongPong check out https://www.drupal.org/project/feeds/issues/2772595 for the empty images issue. Im currently tracking that down, hoping to have a patch soon.
Comment #17
megachrizThe patch in #11 makes error messages to the user less readable. See image.

Comment #18
megachriz@mikran, @HongPong, @wolffereast, @others
Can you provide the full call stack? It just sounds weird that a FormattableMarkup object would throw a TargetValidationException. Like the code is in some sort of loop (though not an infinite one).
I tried to reproduce the error in PHP 7.1.14 today, no luck yet.
Perhaps also useful to know: does the error happen with the Bartik theme? Or do you have a different theme installed? Maybe the theme uses a FormattableMarkup object to render something and it somehow does that before the exception is thrown.
Comment #19
hongpong commented@megachriz yes I do think I saw a loop of some sort going on (like it would seem to complete the batch and start over). It will take a couple days but I should be able to get you something better reproducible.
I have zurb_foundation theme and I do tend to see
<em class="placeholder">tags here and there. So perhaps there is something getting altered in the theme that makes a FormattableMarkup pop up.Comment #20
wolffereast commentedHere is the text of the full error. I'm not seeing much in the way of looping in there, it hits File.php and dies. Im currently running through a cache grind to see if I can track the issue any further.
Comment #21
wolffereast commentedMissed the theme question. I am using the default themes. To be precise I have Bartik 8.5.3-dev and Seven 8.5.3-dev enabled. I just pulled updates, so they should be up to date. The feed runs in the admin theme, so it would be Seven if it is coming from the theme.
Comment #22
wolffereast commentedFrom what I am seeing in core the most common way to set the message of the Exception is to use
parent::__construct();. In this case that would look likeUnfortunately the drupal_set_message call in the catch around line 105 of FieldTargetBase is encoding the html in the message string, which is giving the less than optimal output @megachriz posted above. Because the __construct function is overwritten and methods to retrieve the messageString and args implemented we can trade the
drupal_set_message($e->getMessage());forWith those two changes in place I get the correctly formatted error message shown in the attached thumbnail.
I'm uploading a patch with the two fixes in place just in case this is a legitimate way to handle the output.
Comment #23
megachriz@wolffereast
Thanks for looking into this. Meanwhile, I've worked on test coverage for rendering an error message caused by a ValidationException in #2966515: Add test coverage for display a field validation error.
Comment #24
andypostMostly all over core exceptions use
sprintf()to format exceptions, except ones in which in progress #2055851: Remove translation of exception messagesCore does not use translation for exceptions #2514044: Do not use SafeMarkup::format in exceptions
Looks better to create separate protected method to return messeger (or inject it with constructor)
Comment #25
megachriz@andypost
The issue here is that these messages can be shown to end users. The exceptions here aren't caused by a bug or a bad API call, but by an user interaction. The exceptions are thrown when input validation fails. These messages aren't "developer-facing strings". Therefore I think that in this case the messages should be translated.
Comment #26
megachrizMaybe the code catching the exception should be responsible for marking the message as safe as in install.core.inc:
$e->getMessage()is assigned to'#markup'.Catching a (validation) exception during import happens - among more - in
EntityProcessorBase::process(). It also happens in FieldTargetBase. Maybe it should wrap the message in #markup there? Or we can add a method to ValidationException to return a 'formatted' message.The only downside is that external code that is catching a ValidationException as well, will receive an exception message containing HTML code. And rendering that results into double sanitation.
Comment #27
andypostGot it, then better to catch this exceptions and display user friendly messages to UI
The problem here is that pots and other extraction tools needs real strings in
t()to expose them to translation system... otherwise they will be translatable only at runtime and no way to export them to l.d.oComment #28
megachrizGood news! I've been able to reproduce the error during executing tests from #2940280: Add test coverage for the file target. locally on PHP 7.1.4.
The attached patch makes these test not fail on the error reported in this issue. It also makes error messages thrown in exceptions by the file target translatable.
Comment #30
megachrizAlthough the tests fail on PHP 7.1, PHP 7.2 and D8.6, they did not cause new test failures. The patch even passes on D8.4. So committed #28.
Fixing the test failures for PHP 7.1, etc. is food for another issue.