I am building two modules: one that provides a field type, and one that provides an entity type that automatically creates an instance of that field on the entity during hook_enable(). In hook_uninstall of the entity's module, I'm calling field_delete_instance() and field_delete_field() to mark the field and instance as "deleted" so it can be cleaned up on the next cron run.

When I uninstall the entity module, it successfully marks the field and instance as "deleted." When I run cron, however, the field is deleted from the {field_config} table, but the instance is NOT deleted from the {field_config_instance} table.

After a little digging, I think it is impossible for this to work as expected, based on the code in field.crud.inc. Here's why...

field_purge_batch() is responsible for cleaning up fields and field instances that have been marked as "deleted" in the database. The first thing it does is loads up all the "deleted" instances:

  // Retrieve all deleted field instances. We cannot use field_info_instances()
  // because that function does not return deleted instances.
  $instances = field_read_instances(array('deleted' => 1), array('include_deleted' => 1));

field_read_instances() is used to look up the field instances that are marked as "deleted". However, the function filters out any instances for entity types that don't exist, so they are not returned back to the field_purge_batch() function, and are never deleted.

Here is the code in field_read_instances() that filters out disabled entities:

...
  $instances = array();
  $results = $query->execute();
  foreach ($results as $record) {
    // Filter out instances on unknown entity types (for instance because the
    // module exposing them was disabled).
    $entity_info = entity_get_info($record['entity_type']);
    if ($include_inactive || $entity_info) {
      $instance = unserialize($record['data']);
      $instance['id'] = $record['id'];
      $instance['field_id'] = $record['field_id'];
      $instance['field_name'] = $record['field_name'];
      $instance['entity_type'] = $record['entity_type'];
      $instance['bundle'] = $record['bundle'];
      $instance['deleted'] = $record['deleted'];
      module_invoke_all('field_read_instance', $instance);
      $instances[] = $instance;
    }
  }
  return $instances;

I will be happy to put together a patch to fix this, but I'm not entirely sure what the best approach is.

Why is field_read_instances() filtering out the disabled instances in the first place?

Comments

Not quite sure why nobody else has responded to this, but we have just come across the exact same problem, and since it functionally means you can't properly clean up on your modules uninstallation I would have though more people would be worried about this.

As a temporary measure we have written our own version of field_purge_batch to be used, but I think its worth having the discussion about how this should be resolved properly. I am not entirely sure why field_purge_batch doesn't pass the include_inactive flag, I can't think of any reason why you would have a field marked as deleted that shouldn't be purged just because the entity is inactive.

Same Issue in drupal 7.12.
I agree with you, fields instances from table field_config_instance are marked as deleted but never removed. Although you run cron, execute field_purge_batch() or empty cache.
when you get this situation instances will nerver be removed becouse in field_read_instances() it joins field_config_instance with field_config tables and as field config has been removed ¿?¿?

<?php
  $query
= db_select('field_config_instance', 'fci', array('fetch' => PDO::FETCH_ASSOC));
 
$query->join('field_config', 'fc', 'fc.id = fci.field_id');
 
$query->fields('fci');
?>

but why are removed config before instances¿? if my code does it the oposite.

the code to remove field is

<?php
  $field
= field_info_field('field_name');
  if (!empty (
$field)) {
     
// Fetch the instance (object)
   
$field = field_info_instance('entity_name', 'field_name', 'entity_name');
   
// Delete it.
   
field_delete_instance($field);
   
// Fetch the instance (object)
   
$field = field_info_field('field_name');
   
// Delete it
   
field_delete_field($field);
  }
?>

Any clue?

confirmed, using field_collection

Version:7.12» 7.x-dev

I haven't tested this recently, but the version should be 7.x-dev. Not 7.12... otherwise it will get swept under the rug.

I also have the same problem and I don't know if I should fix myself or Drupal core team will fix this problem because we are not supposed to modify any Drupal core files.

Same here, field_config row already deleted while field_config_instance not, so the join prevents any further deletion.
I'm developing a custom module and this lead me to a lot of orphaned rows into field_config_instance table (after some module install/uninstall).

Is anybody working on this?

I ran into the same issue, and as well it's not clear to me why field_read_instances() filters out field instances on unknown entity types.

The workaround I used was to put all of the field/entity type creation hooks into one module, and all of the field base/instance creation (and removal) into another module. Then make the latter module dependent on the former. This ensures the entity type is available when uninstalling your module set.