How can I remove items from the allowed values list of a select field that has data for the values?
I did something like this recently with the following approach.


Add the new allowed values.
Add a setting to configure "active" values.
Filter out the "inactive" values from display on the form.


e.g:

/**
 * Admin settings form
 */
function MODULE_admin_settings(){

  $form = array();

  // Select active preferences for display
  $field = field_info_field('field_preferences');
  $preferences = list_allowed_values($field);
  $form['field_preferences_active'] = array(
    '#type' =&gt; 'checkboxes',
    '#title' =&gt; t('Active preferences'),
    '#options' =&gt; $preferences,
    '#description' =&gt; t('Select the preferences available for user selection.'),
    '#default_value' =&gt; variable_get('field_preferences_active', array()),
  );

  return system_settings_form($form);

}

/**
 * Implements hook_field_attach_form
 */
function MODULE_field_attach_form($entity_type, $entity, &amp;$form, &amp;$form_state, $langcode) {

  // Filter out inactive preferences
  if(isset($form['field_preferences'])){
    $preferences = variable_get('field_preferences_active', array());
    foreach($preferences as $key =&gt; $preference){
      // If this preference isn't checked, but is set in the field values, unset it.
      if(empty($preference) &amp;&amp; isset($form['field_preferences'][LANGUAGE_NONE]['#options'][$key])){
        unset($form['field_preferences'][LANGUAGE_NONE]['#options'][$key]);
      }
    }
  }

}


This way the legacy data is preserved for reference, the form validates, and the data integrity is intact.