hook_validate() returns errors, but the form has lost all the user's submitted values
There is nothing particular that needs to be done, to avoid to overwrite the value entered by the user, when a validation handler returns an error.

For example, the following form, is build from the code shown below (system_ip_blocking_form()):



function system_ip_blocking_form($form, $form_state, $default_ip) {
  $form['ip'] = array(
    '#title' =&gt; t('IP address'), 
    '#type' =&gt; 'textfield', 
    '#size' =&gt; 48, 
    '#maxlength' =&gt; 40, 
    '#default_value' =&gt; $default_ip, 
    '#description' =&gt; t('Enter a valid IP address.'),
  );
  $form['actions'] = array('#type' =&gt; 'actions');
  $form['actions']['submit'] = array(
    '#type' =&gt; 'submit', 
    '#value' =&gt; t('Add'),
  );
  $form['#submit'][] = 'system_ip_blocking_form_submit';
  $form['#validate'][] = 'system_ip_blocking_form_validate';
  return $form;
}


Its validation handler is the following one (system_ip_blocking_form_validate()):

function system_ip_blocking_form_validate($form, &amp;$form_state) {
  $ip = trim($form_state['values']['ip']);
  if (db_query("SELECT * FROM {blocked_ips} WHERE ip = :ip", array(':ip' =&gt; $ip))-&gt;fetchField()) {
    form_set_error('ip', t('This IP address is already blocked.'));
  }
  elseif ($ip == ip_address()) {
    form_set_error('ip', t('You may not block your own IP address.'));
  }
  elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE) == FALSE) {
    form_set_error('ip', t('Enter a valid IP address.'));
  }
}


When I enter a value for which the validation handler returns an error, the value I enter is not modified, as you can see from the following screenshots.





This is what happens on Drupal 6 too. The only case where a field value is cleared is when the form validation handler reports an error for a password form field; in that case the password field doesn't contain the previously entered password, which would be difficult to edit as it is shown as "•••••."

There is nothing that needs to be set; by default Drupal will not change the content of a field when a validation handler reports an error for that field. As far as I know, the value of a field could be changed by its "#after_build" callback, that is invoked after the field is built, and that is described in form_builder() with the following sentence:


  The "#after_build" flag allows any piece of a form to be altered after normal input parsing has been completed.