Problem/Motivation
After update I randomly get this error, but did not create any bundle classes. One time it loads the entity, other time it does not load the same entity. I will update issue as I understand more why this is happening.
TypeError: Return value of Drupal\Core\Entity\EntityStorageBase::getEntityClass() must be of the type string, null returned in Drupal\Core\Entity\EntityStorageBase->getEntityClass() (line 115 of /web/core/lib/Drupal/Core/Entity/EntityStorageBase.php)
#0 /web/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php(196): Drupal\Core\Entity\EntityStorageBase->getEntityClass()
#1 /web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php(508): Drupal\Core\Entity\ContentEntityStorageBase->getEntityClass()
#2 /web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php(427): Drupal\Core\Entity\Sql\SqlContentEntityStorage->mapFromStorageRecords()
#3 /web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php(393): Drupal\Core\Entity\Sql\SqlContentEntityStorage->getFromStorage()
#4 /web/core/lib/Drupal/Core/Entity/EntityStorageBase.php(346): Drupal\Core\Entity\Sql\SqlContentEntityStorage->doLoadMultiple()
#5 /web/core/lib/Drupal/Core/Entity/EntityStorageBase.php(296): Drupal\Core\Entity\EntityStorageBase->loadMultiple()
#6 ...: Drupal\Core\Entity\EntityStorageBase->load()
Comments
Comment #2
mindaugasd commentedSolved this by adding few lines of custom code.
It was happening within Batch API, halting the long running progress randomly.
Comment #3
fgmSame problem here with 9.3.5. I'm within a batch too:
Comment #4
fgmThe relevant difference is that the same $this->storage->loadMultiple() works normally outside a batch: seems batch loops miss some entity system initialization. These same nodes can be loaded:
Drupal\node\Entity\Node::loadMultiple($ids);callThis looks like it could also be related with https://www.drupal.org/project/drupal/issues/3244802, which changes EntityStorageBase::__set and marks it deprecated.
Comment #5
fgmI did a bisect on our project and the bug appeared at some point between 9.2.12 (working) and 9.3.0 -alpha1 (failing): that limits the potential causes.
We didn't catch it because none of our tests cover batches.
Comment #6
fgmFinished the bisect. The problem appears with revision 02912a44b1363d838a3e906a7f12709481754b8d : the fix for #3246150: Bundle class changes mean the entity class is now determined by the active entity-type definition, which does change
EntityStorageBasewhere the problem is located.Comment #7
berdirI can't explain why baseEntityClass would suddenly be empty and sometimes not. What exactly happens *before* that other issue? an empty string is just a wrong and bogus as NULL and should fail as well one step later, when trying to create that class.
Comment #8
fgmIt's a pretty basic batch, in which steps load a chunk of nodes, update one of its field items, and store the node back. Returning "" from that function does not cause further errors in my case. We don't have more details from the OP, except that it was also in a batch.
Comment #9
fgmHey @mindaugasd can you provide more detail, as our cases seem to resemble each other ?
Comment #10
mindaugasd commentedI wrote all the relevant details that I had. My PHP version is 7.4.27 (but maybe PHP version was different back then)
I solved issue with a patch.
Unless you could ask me very specific things to do that would be of some benefit.
And I would need to construct a new kind of batch, because existing one is very slow, complex and not suitable for testing.
Or - we can just use a patch, and maybe the problem reveal itself or be solved in some other context later.
Comment #11
fgmNew finding: during the batch,
$this->getEntityClass()gets called on aNodeStoragefor which the constructor was never called.After further digging, this happens because the NodeStorage is deserialized in Core\Queue\Batch::claimItem and does not contain that field.
Comment #12
berdirah, now that does make sense.
the private property that we have is breaking DependencySerializationTrait. Change it to protected and it will work.
That said, I strongly recomend to never inject/store storages in a property, inject the entity type manager and get the storage when you need it. See #3162827: Do not instantiate entity storages in constructors of services that do not always need them
Comment #13
fgmAdding Berdir's link to #3162827: Do not instantiate entity storages in constructors of services that do not always need them.
Comment #14
fgmThe problem is that if we put the ETM in a batch info instead of the storage, we now get an assertion failed "The container has been serialized" in
DatabaseQueue::createItem()because the batch items now contain a service, and since they are arrays by Batch API specification, they cannotuse DependencySerializationTrait.In my case, I just removed it altogether and made the batch operations callback a normal method instead of a static one, and added the
DependencySerializationTraitto allow as an instance method, hence needing to serialize the service carrying it. Another solution would have been to useDrupal::entityTypeManager()but that triggers coder warnings.Thanks for your help finding the issue. We probably want to handle #3197773: add documentation about not injecting entity storage handlers which would have avoided this, now.
Comment #15
berdirLets keep this open for now, I do think we should think about not using private there.
Comment #18
mindaugasd commentedComment #20
joseph.olstadDrupal 11.1.1
key module 1.x-dev latest as of today
key module 1.19 also affected
symfony mailer lite: 2.0.2
Operation: add a key-override for the smtp username and smtp password of the symfony mailer transport configuration.
The path of the request:
/admin/config/development/configuration/key-overrides/add?ajax-formSame exact error as illustrated above: