I'm here because of this:

EntityMalformedException: Missing bundle property on entity of type contacts. in entity_extract_ids()

I'm trying to create my own entity. Can you identify what is incorrect or missing about my entity configuration?

I am using the Creating your own entities with Entity API guide for setting up a new module using entities.

For my needs, I only need one entity type. The example creates two entity types, one called "task", and another called "task_type". So I did my best to eliminate the "task_type" sections, but I'm getting the above error and am not understanding what to do about the bundle type.

This is my hook_entity_info().

 * Implements hook_entity_info().
function contacts_entity_info() {
  $return = array(
    'contacts' => array(
      'label' => t('Contact'),
      'entity class' => 'Contacts',
      'controller class' => 'ContactsController',
      'base table' => 'contacts',
      'fieldable' => TRUE,
      'entity keys' => array(
        'id' => 'ckid',
      'bundle keys' => array(),
      'bundles' => array(),
      'load hook' => 'contacts_load',
      'view modes' => array(
        'full' => array(
          'label' => t('Default'),
          'custom settings' => FALSE,
      'label callback' => 'entity_class_label',
      'uri callback' => 'entity_class_uri',
      'module' => 'contacts',
      'access callback' => 'contacts_access',

  return $return;

This is my custom controller. (Do I even need this?)

class ContactsController extends EntityAPIController {
  public function create(array $values = array()) {
    global $user;
    $values += array(
      'mail' => '',
      'notes' => '',
      'created' => REQUEST_TIME,
      'changed' => REQUEST_TIME,
      'uid' => $user->uid,
    return parent::create($values);

  public function buildContent($entity, $view_mode = 'full', $langcode = NULL, $content = array()) {
    $wrapper = entity_metadata_wrapper('contacts', $entity);
    $content['author'] = array('#markup' => t('Created by: !author', array('!author' => $wrapper->uid->name->value(array('sanitize' => TRUE)))));

    // Make Description and Status themed like default fields.
    $content['notes'] = array(
      '#theme' => 'field',
      '#weight' => 0,
      '#title' =>t('Notes'),
      '#access' => TRUE,
      '#label_display' => 'above',
      '#view_mode' => 'full',
      '#language' => LANGUAGE_NONE,
      '#field_name' => 'field_contact_notes',
      '#field_type' => 'text',
      '#entity_type' => 'contacts',
      '#items' => array(array('value' => $entity->notes)),
      '#formatter' => 'text_default',
      0 => array('#markup' => check_plain($entity->notes))

    return parent::buildContent($entity, $view_mode, $langcode, $content);

1 Answer 1


entity_extract_ids() raises an exception when $info['entity keys']['bundle'] is not defined, or is an empty string. If you don't want to explicitly set the bundle property, you need to set it to value that is considered empty from PHP, but it is not an empty string, such as an empty array, or FALSE. In such cases, the bundle property is set to the entity type name.

The following is the code contained in entity_extract_ids(), and which raises the exception you are seeing.

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)));
  $bundle = $entity->{$info['entity keys']['bundle']};
else {
  // The entity type provides no bundle key: assume  single bundle, named
  // after the entity type.
  $bundle = $entity_type;

Keep in mind that entity_get_info() caches the entity information it gets. If you edit an enabled module, you need to disable it, and re-enable it. This forces Drupal to clean the cache it uses, and call the implementations of hook_entity_info() to get a fresh definition of the entity.

  // Use the advanced drupal_static() pattern, since this is called very often.
  static $drupal_static_fast;
  if (!isset($drupal_static_fast)) {
    $drupal_static_fast['entity_info'] = &drupal_static(__FUNCTION__);
  $entity_info = &$drupal_static_fast['entity_info'];

  // hook_entity_info() includes translated strings, so each language is cached
  // separately.
  $langcode = $language->language;

  if (empty($entity_info)) {
    if ($cache = cache_get("entity_info:$langcode")) {
      $entity_info = $cache->data;
    else {
      $entity_info = module_invoke_all('entity_info');
      // Merge in default values.
      foreach ($entity_info as $name => $data) {
      // …
    // …

Installing a new module has the same effect, as Drupal should clear its cache in that case too. If it doesn't happen, you can always force Drupal to clear its cache with cache_clear_all('entity_info', 'cache', TRUE).

  • So I modified my contacts_entity_info() from above so that 'entity keys' includes 'bundle' => array(), and I've also tried 'bundle' => FALSE, and 'bundle' => NULL, but it isn't working. I get the exact same error message. I'm wondering if there's a call to entity_create() that's causing this? Dec 3, 2012 at 18:36
  • 1
    If you have modified an enabled module, you need to disable, and re-enable it. Drupal caches the entity definitions, and disabling a module forces Drupal to clean its cache.
    – apaderno
    Dec 3, 2012 at 19:37
  • That did fix the problem. I really thought "Clear all cache" would have done it, but after disabling and re-enabling, it works great. I'd say thanks but you'd probably edit it out. :) Dec 3, 2012 at 21:16
  • The way to be sure Drupal clear any caches containing module-related data is to disable, and re-enable a module, or to install a new module. If, for example, you call cache_clear_all() without any argument, what you obtain is clearing some specific cache tables, which contain data used to render a page, and which are minimally related to a module (cache_block, and cache_page).
    – apaderno
    Dec 3, 2012 at 23:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.