PHP Fatal error: Class name must be a valid object or a string in /var/www/html/includes/common.inc on line 7779, referer: [site]

I have traced this down to the MCAPI module/library. I will enable: Mailchimp Integration, Campaign & Lists. Once they are enabled, all 9 of my sites will work properly, then, out of the blue, they all start throwing the above error. So I truncate the cache table and all works again. I haven't isolated it to the exact module yet. I will be doing that tomorrow. But here is a place to start.

I'm running Open Public on the latest drupal core with all modules up to date, my status page states that MCAPI is installed properly.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

lilott8’s picture

May 2 10:31:32 www01 drupal: [site]|1367508692|Pumpkin|208.115.113.88|[site]||0||Class errori mailchimp_list

this looks to be mailchimp_list as the problem. I added some logging to common.inc at 7779.

gcb’s picture

Status: Active » Postponed (maintainer needs more info)

lilott8, I am unable to reproduce and really not sure how to try to reproduce. Can you give any more detailed analysis than "mailchimp_list" is the problem?

levelos’s picture

Status: Postponed (maintainer needs more info) » Closed (cannot reproduce)
jp.stacey’s picture

Title: PHP Fatal Error: class must be a valid object/string » Core entity_get_controller gets a NULL controller class
Project: Mailchimp » Drupal core
Version: 7.x-2.x-dev » 7.22
Component: General » entity system
Status: Closed (cannot reproduce) » Active
FileSize
1.68 KB

This isn't a Mailchimp specific issue: we've just had the same problem with Redirect, and I think it could be a more general edge case with entity_get_info().

The issue seems to be that somehow entities of a certain type end up with no entity info, and hence a NULL controller class. There's no checking in includes/common:7779 that the class actually exists, and so the PHP fatal error is then thrown. I've attached a stack trace with the node content edited out for clarity.

One complication with our site is that we've got i18n and entity translations switched on: for a start, that means that during the module enabling phase, translations get downloaded; but also that might add a layer of indirection to the code.

However, I'm not so bothered about why it happens, as to how we can somehow rebuild the entity type info cache and get the controller class recognized! Anyone know how we can do that? We've tried enabling, re-enabling, completely uninstalling; we've tried clearing caches in the admin interface and at the command prompt with drush; and if we sync the code and database with a local dev version, the problem is not repeatable....

jp.stacey’s picture

Update: one quick but very ugly fix is to run the following, somewhere:

  $langcode = "en";
  cache_clear_all("entity_info:$langcode");

for all language codes you use: in this example, I've run it for "en", but you should run it (and check node editing/entity translation) for every language code you use.

However, if you're using a weird cacheing strategy (e.g. this site is using APC as a data cache) then you might need to actually run this from within the production webserver, as running it at the command line won't clear the cache. If so, then - carefully - hack entity_get_info() and run the cache_clear_all() after the line:

function entity_get_info($entity_type = NULL) {
  /* ... */
  $langcode = $language->language;
  cache_clear_all("entity_info:$langcode"); /* <- HERE! */
  /* ... */
}

Ugh. But it does seem to have worked for us; fingers crossed.

It's possible that whether or not you even see this edge case depends on your cacheing strategy. Yet it's very weird that those caches weren't being emptied either on a cache clear or on a module (re-)enable.

longwave’s picture

There are re-entrancy issues if a module calls entity_load() during a rebuild of the entity cache (ie. from within hook_entity_info()). Not sure if this affects core directly but it does affect users of Entity API: See https://drupal.org/node/1313238 and #1290986: avoid entity_load() during entity info cache rebuilds

sunset_bill’s picture

+1
I'm getting this same thing. Some debug code in entity_get_controller shows that I am getting a valid class name for my entity, and I've verified that the class named really does exist in my entity code. I tried the #5 hack, but it didn't help. I've also tried drush updb and drush cc, per some other posts I've seen, but no joy there, either This is really perplexing because it's causing my attempts at simpletests to crash.

Leeteq’s picture

Version: 7.22 » 7.x-dev
Exploratus’s picture

I am also getting this problem with mailchimp

Exploratus’s picture

Issue summary: View changes

removing log info.

mcdruid’s picture

Agree that core should be more careful about trying to instantiate non-existent classes.

Perhaps it would be a good idea to log something about the problem, rather than silently giving up though?

Here's a patch with a small tweak in order to be even more careful about Fatal errors due to messed up entity metadata, and which logs a warning if the controller class can't be loaded for a given entity type.

g33kg1rl’s picture

The patch in #11 throws this error for me.

Error message
EntityMetadataWrapperException: Invalid data value given. Be sure it matches the required data type and format. in EntityMetadataWrapper->set() (line 122 of sites/all/modules/entity/includes/entity.wrapper.inc).
×

After I try to add a link to the main menu while saving a node.

mcdruid’s picture

@g33kg1rl I can't reproduce that error (which appears to come from the contrib entity module) using a vanilla install with the patch from #11 and:

$ drush rl drupal entity
 Project  Release      Date         Status
 drupal   7.x-dev      2017-Feb-01  Development                                             
 entity   7.x-1.8      2016-Sep-22  Supported, Recommended, Installed

(actually drupal-7.x git HEAD)

I tried creating both a Basic page and an Article, and creating a menu link placed in the Main menu for each.

I don't see any errors or warnings, and particularly not a Fatal.

It looks like you'd get that if the EntityMetadataWrapper->validate method returned FALSE, which could happen for a few different reasons.

Are you sure that the patch introduces the error? What happens without the patch?

g33kg1rl’s picture

EDIT: Turns out it was an issue with the Boost module. Sorry for any confusion.

I upgraded entity to the latest module. I will also upgrade Drupal to the latest version. I receive these errors after saving a basic page with a corresponding menu item.

Without the patch, I receive the following error:

PHP Fatal error: Class name must be a valid object or a string in includes/common.inc on line 7999

With the patch I receive:

Notice: Undefined index: name in EntityMetadataWrapper->debugIdentifierLocation() (line 246 of /var/aegir/platforms/***/sites/all/modules/entity/includes/entity.wrapper.inc).
EntityMetadataWrapperException: Invalid data value given. Be sure it matches the required data type and format. Value at : %. in EntityMetadataWrapper->set() (line 122 of /var/aegir/platforms/***/sites/all/modules/entity/includes/entity.wrapper.inc).

When applying the patch it said:
Hunk #1 succeeded at 7957 (offset -49 lines).
Hunk #2 succeeded at 7992 (offset -49 lines).

I hope this is helpful. Let me know if you have any other suggestions.

hgoto’s picture

I saw the patch #11.

-    $class = $type_info['controller class'];
-    $controllers[$entity_type] = new $class($entity_type);
+    if (isset($type_info['controller class']) && class_exists($class = $type_info['controller class'])) {
+      $controllers[$entity_type] = new $class($entity_type);
+    }
+    else {
+      watchdog('unknown entity type', $entity_type, NULL, WATCHDOG_WARNING);
+      $controllers[$entity_type] = NULL;
+    }

It would be better if the log message is more precise. The case that $type_info is NULL (the entity type is not found) and the case that $class doesn't exist are different.

Also, I think it might be better to raise an error if the entity type or the controller class is not found because such cases are completely wrong processes.

caspervoogt’s picture

patch #11 solved this for me. Good points in #15, @hgoto.

Oualid-EZR’s picture

#11 patch worked! #15 nice reflection.
Thanks.

capysara’s picture

I applied the patch in #11 and it addressed the issue described.

However, FWIW, my site still won't load because I get all new errors, even after clearing the cache a couple of times. I don't know if these issues are related or something else entirely, but I thought I would document in case someone else has the same experience. After the first cache clear I see:
* WD unknown entity type: rules_config
* several 'Invalid argument supplied...'
* Missing database columns for the exportable entity rules_config as defined by entity_exportable_schema_fields(). Update the according module and run update.php! entity.module:874
* Argument 2 passed to SelectQuery::fields() must be of the type array, null given, called in /Sites/www/includes/entity.inc on line 317 and defined select.inc:1316

With another cc all, I just get: PHP Catchable fatal error: Argument 2 passed to SelectQuery::fields() must be of the type array, null given, called in /Sites/www/includes/entity.inc on line 317 and defined in /Sites/www/includes/database/select.inc on line 1316.

Drush rr gets my site back up and running (with or without the patch).

mcdruid’s picture

Looked at the latest patch again; I do agree that the logging:

    $type_info = entity_get_info($entity_type);
    if (isset($type_info['controller class']) && class_exists($class = $type_info['controller class'])) {
      $controllers[$entity_type] = new $class($entity_type);
    }
    else {
      watchdog('unknown entity type', $entity_type, NULL, WATCHDOG_WARNING);

Isn't very precise; it's the fact that the controller class either isn't in the $type_info or is not a valid class which is causing a problem here. However, the $type_info for a given entity can be quite a large array so I'm not sure we want to try and do something like print_r all of it into a log message. Plus - as the code stands - we don't know whether the $type_info['controller class'] element was actually there or not.

On the other hand, elsewhere in core a similar error is handled a bit differently:

function entity_extract_ids($entity_type, $entity) {
  $info = entity_get_info($entity_type);

[...snip...]

  if (!empty($info['entity keys']['bundle'])) {
    // Explicitly fail for malformed entities missing the bundle property.
    if (!isset($entity->{$info['entity keys']['bundle']}) || $entity->{$info['entity keys']['bundle']} === '') {
      throw new EntityMalformedException(t('Missing bundle property on entity of type @entity_type.', array('@entity_type' => $entity_type)));
    }

Anyone who has come across this happening on a site will know that it's quite painful as I believe it typically ends up being a Fatal e.g.:

PHP Fatal error:  Uncaught exception 'EntityMalformedException' with message 'Missing bundle property on entity of type node.'

...but it does reflect the fact that something's seriously wrong with some of the entity metadata in the system.

I wonder if we should be looking at taking a similar approach here... in the interests of consistency if nothing else.

mcdruid’s picture

Patch which implements the pattern from entity_extract_ids() i.e. throw an exception if the entity is malformed (missing a valid controller class).

This is more consistent with what's already in core, but less forgiving of messed up entities than the previous patch.

You could argue these exceptions shouldn't be uncaught, but I think that's out of scope here (and probably not something I'd expect to change in D7 at this stage).

Status: Needs review » Needs work

The last submitted patch, 20: 1982810-20.patch, failed testing. View results

mcdruid’s picture

Status: Needs work » Needs review

testbot?

Status: Needs review » Needs work

The last submitted patch, 20: 1982810-20.patch, failed testing. View results

joseph.olstad’s picture

joseph.olstad’s picture

Status: Needs work » Needs review

triggering testbot

mcdruid’s picture

Tests passed on retest this time.

Anyone able to review?

joseph.olstad’s picture

Has anyone tried to fix this in the MCAPI module/library ?

mcdruid’s picture

From #4:

This isn't a Mailchimp specific issue: we've just had the same problem with Redirect, and I think it could be a more general edge case with entity_get_info().

IIUC the mailchimp module is/was a usual suspect here, but there are many other ways a site can end up hitting this situation.

poker10’s picture

I have tested the patch and it looks good. I prefer this approach (#20), because if you try to use wrong entity type, or entity type without a controller class, it could only get worse if we does not stop the code from being executed further.

There is a good example of one possible case to simulate the error here: #1667536-21: PHP Fatal error: Class name must be a valid object or a string in drupal-7.14/includes/common.inc on line 7680

$entity_type = arg(0);
$entity_id = arg(1);
$entity = entity_load($entity_type, $entity_id);

The entity_load() will call entity_get_controller() function and this function will try to load the entity info and controller class. The function entity_get_info() can return NULL or array of all entities, if the parameter $entity_type is empty or it is non-existent entity type. In this case, controller class will be NULL and the entity_get_controller() will try to instantiate empty class. So we will get:

Warning: Trying to access array offset on value of type null in entity_get_controller() (line 8168 of includes/common.inc).
Error: Class name must be a valid object or a string in entity_get_controller() (line 8169 of includes/common.inc).

After applying the patch #20, we will get:

EntityMalformedException: Missing or non-existent controller class on entity of type test. in entity_get_controller() (line 8170 of includes/common.inc).

I have added a simple test for two usecases and reuploading with test only version. The original patch is unchanged. I did not have "luck" to simulate the second usecase (where the controller class is somehow NULL) on the real D7 site (with Mailchimp, or other module).

The last submitted patch, 29: 1982810-29_test-only.patch, failed testing. View results

poker10’s picture

Issue tags: +Needs change record