I'm not exactly sure what is going on here but I've finally managed to find a way to reproduce this error consistently.
Set up
- Create a content type with an image field
- Add an entity reference field that references "Other > Configuration > Block"
- Ensure you have a View on the site with a block display (e.g. "Who's Online") and that it is placed in a region
Steps
- Create a node and in the block entity reference field, choose your Views block (e.g. "Who's Online")
- Save the node - the views block should render fine
- Open the node for editing
- Upload an image in the image field
- The ajax should fail and you should get the error below on screen in your inspector console, failing that it might appear on node save.
Fatal error: Call to a member function getFieldStorageDefinition() on array in core/lib/Drupal/Core/Field/TypedData/FieldItemDataDefinition.php on line 66
Line 66 is return $this->fieldDefinition->getFieldStorageDefinition()->getPropertyDefinitions();.
From a bit of debugging, I can see that $this->fieldDefinition is indeed an array and contains the following: Array ( [class] => Array ( [0] => node-page-edit-form [1] => node-form ) [data-drupal-selector] => node-page-edit-form )
The above steps reproduces the error consistently for me. I've noted the following however:
- There's no issue editing fields which do not rely on AJAX (e.g. title field)
- You can reference regular blocks or custom block types and you won't get the error. It only happens with Views blocks afaict
- I've used the image uploader as a simple way to trigger it, but any ajax operation on the page should trigger it.
Comments
Comment #2
stella commentedComment #3
samuel.mortensonI'm also seeing this intermittently with Panels IPE, but for me
$this->fieldDefinitionis a string containing the Plugin ID of the Block I'm placing.Comment #4
samuel.mortensonThis is possibly related to #2443165: Drupal\Core\Entity\EntityInterface\ContentEntityStorageBase::doCreate() assumes that the bundle is a string.
Comment #6
cman9090 commentedI'm getting this exact same issue. Same steps to reproduce error. I've tried following https://www.drupal.org/node/2443165 and all related nodes, nothing has helped.
Comment #7
shadcn commentedI can still reproduce this on 8.4.x.
It looks like this is coming from
entity_reference_autocomplete. If I switch the block reference field to a select list, error is gone.@cman9090 can you confirm this please?
Comment #8
berdir#2831521: Avoid unserialization of blockPluginCollection in BlockDisplayVariant is related, which fixes many such problems in page_manager/panels.
Haven't seen it yet just in core, but it is probably something else that is getting serialized and shouldn't and then causes unserialize bugs.
Note: Block entity reference fields, the standard reference field? That's IMHO the wrong way to do that, consider using the block_field project instead which allows to reference the block *plugin* and not a block config entity, which is designed and built to be displayed in a specific theme in a region, with visibility conditions.
Comment #9
pingwin4egI have the same error, but with another case.
I try to run operations in a batch from a views bulk form on entities of a custom type. The view has an argument - the entity reference field, which refers to an entity of another custom type by numeric ID. Both entity types are Content Entity Types. This view arg has a validation checkbox checked, that current user must have a 'view' access on referenced entity. This referenced entity has 'uid' field as a reference to entity owner. An error occurs in this 'uid' field, when the access handler attempts to fetch the owner ID from an entity.
Here is my error backtrace.
The weird thing is that the guilty array contains something that I didn't expect to see:
Comment #10
hazaGot more or less the same issue, trying to execute (or preview) a views using a searchAPI as backend in a batch operation.
Comment #11
berdirAs I said, all of those indicate very large objects being serialized that then result in bugs on unserialize, which looks like a PHP bug then.
Something is not properly using DependencySerializationTrait as the ctools example above, maybe core, maybe some other module like search_api. The only way to figure this out is try to look at the serialized data structures being created in cache/key_value_expire, and trying to figure out what kind of object you have in ther that is so bug and messing up everything.
Comment #12
shadcn commented@Berdir for my test in #7, this was with core 8.4.x (no contrib):
\Drupal\Core\Field\TypedData\FieldItemDataDefinition::getPropertyDefinitions.I'll look into this a bit more tomorrow.
Comment #13
pingwin4egI've debugged my case a little. And found that the fieldDefinition property is serialized as a reference (
r:49;) when being cached. I didn't count 49 items, but as far as I understood it refers to proper BaseFieldDefinition object. So I guess the problem is with UNserialization here.@Berdir are you proposing to remove the fieldDefinition property before serializing an object (like it's done with block plugins in a mentioned issue)?
Comment #14
berdirI'm not sure what object needs to be removed, likely not the field definition, we can only remove services that we can re-inject or things that we can re-create like plugin collections. A field definition should be a simple object without external dependencies.
your dump looks small to me, not sure why that would be a problem. Mine that failed where multiple hundred kilobites and had *everything* in them.
On the other hand, yours might be small enough so you could re-create it in a more or less standalone PHP script. Then we might be able to create a php bug report.
Comment #15
berdirI'm not sure that's the right cache entry though. Can you post a full backtrace of where this happens?
Comment #16
pingwin4egHere is the initial backtrace when the Error happens: https://gist.github.com/mikeshiyan/3f6342f8f870a49443eca5dd540893ae - when the method is called on array. Then I started to debug that trace from the beginning of request to find when the fieldDefinition property becomes an array.
I found out that before
Drupal\Core\Entity\ContentEntityBase->getTranslatedField('uid', 'x-default')the property is not set yet. From that point:$cid = 'entity_base_field_definitions:' . $entity_type_id . ':' . $this->languageManager->getCurrentLanguage()->getId(); and EntityFieldManager service uses @cache.discovery as backend.And cache is in place. I tried to delete this entry and return back to page from which I start the batch process. It renders without an error, and this cache entry is recreated here. Perhaps that page even uses this cache entry when it exists (I didn't test), so unserialization by itself should not be the problem.
But when I see the result of cacheGet() the array is already there in fieldDefinition property. So right now I can't understand how is that even possible.
P.S.: I forgot to mention I use core 8.2.5 in my project. Maybe in later versions field definitions are stored in another cache bin? I haven't checked it yet.
Comment #17
cman9090 commented@arshadcn can confirm using autocomplete with block config reference. I've built an entire portal 100's of nodes are populated with entity block config references so redoing it with block_field is not my first go-to. I've changed the form display from autocomplete to select list and it appears to be working now.
Comment #18
pingwin4egI think I found the cause. Seems like a PHP bug in unserialize() function. Precisely in nested unserialization.
Let's look at my case, for example.
The last serialized string (the cached entity_base_field_definitions item) contains references (like
r:2,r:49, etc.) The numbers refer to objects from the current serialized string. But, nobody knows why, in the unserialization process the values from the very 1st serialized string are assigned instead (in preserved order).So in my case the
r:2, which should be the BaseFieldDefinition object for the 'sid' field, on unserialization becomes the batch 'sets' array. Andr:49, also the BaseFieldDefinition object but for the 'uid' field, becomes a{["data-drupal-selector"]=>"edit-show-view-elements"}array, which also present in $batch array.Comment #19
pingwin4egThere's already a 3-year-old bug report @ https://bugs.php.net/bug.php?id=66052
Comment #20
shadcn commented@cman9090 I mean you don't need to change the field. You can just change the widget.
Comment #21
pingwin4egThis is a very-very rough workaround of the nested unserialize() bug. It covers only cases with Views and Database cache backend.
Don't use it on live projects. Seriously. Just for development.
Comment #23
pingwin4egCreated a new issue, specifically for the unserialization bug. Seems like all reports here in this issue are caused exactly by it.
Comment #24
mxh commentedThe only thing I have noticed so far is that in
ViewExecutable, when its::serialize()method calls the PHP functionserialize()- whether or not returned its value - leads to the problem.Example (seems to only apply for
ViewExecutable):When commenting out the line with the serialize-instruction, the data corruption is not happening...
Comment #25
mxh commentedTrying to write the cause of this problem into the title for better addressing.
I'm also changing the affected component, since this issue is very likely a common object serialization problem.
Feel free to change it if it's still not suitable.
Attaching a patch which replaces the Serializable implementation by an alternative using magic methods.
By this, I also removed the usage of DependencySerializationTrait, because it seems that it had no use anyway (
__sleep()and__wakeup()aren't used anymore when a class implements the\Serializableinterface). I haven't found any other point where this might be relevant, thus removed.Comment #26
mxh commentedChanging the component again, sorry - the cause of the issue here solely belongs to the views module (but it might be still a common serialization problem).
Comment #27
pingwin4eg@mxh There's a separate issue specifically for serialization in Views - #2849674: Complex job in ViewExecutable::unserialize() causes data corruption. And THIS issue might have different source(s) of a problem (as per various reports) - we can't be certain for now. Please move your patch to that issue, and let's discuss it there. And lets return this issue its title.
Comment #28
mxh commentedAs you wish.
Comment #29
mxh commentedTo review and discuss patch from comment #25, please go to #2849674: Complex job in ViewExecutable::unserialize() causes data corruption
Comment #30
patrick.thurmond@gmail.comI am having a similar problem except instead of "on Array()" my error is "on null". Definitely a show stopper.
Comment #33
techwolf12 commentedPatch doesn't work on 8.5.x
Comment #34
mxh commentedWhich patch @techwolf12? Approach of #25 is already in 8.5.x, see also #2849674: Complex job in ViewExecutable::unserialize() causes data corruption
Otherwise please provide some details about your occurred problem.
Comment #36
drholera commentedAny update on this issue? I have the same issue as @pthurmond in #30, error "on null". I think it's related to some broken configs but cannot find with what exactly ones.
Comment #42
mvonfrie commentedI have the same error "on null", but interestingly only for a few random (but always the same) entities of a specific entity type (a group membership). The exact error message is
Comment #45
quietone commentedI tested this today on Drupal 11.x, standard install, following the steps in the Issue Summary. I did not get a fatal error when adding an image in the image field. Therefor, I am closing this as outdated.
If you are experiencing this problem on a supported version of Drupal reopen the issue, by setting the status to 'Active', and provide complete steps to reproduce the issue (starting from "Install Drupal core").
Thanks!