Last form validation function is passing an error even though the first one registers the user I wrote a custom user_login form validation function that calls user_external_login_register() to register and login the user, but the last validation function for the form calls form_set_error().

The form's #validate array looks like this:

validate (Array, 4 elements)

    * 0 (String, 32 characters ) vtiger_portal_user_form_validate
    * 1 (String, 24 characters ) user_login_name_validate
    * 2 (String, 32 characters ) user_login_authenticate_validate
    * 3 (String, 25 characters ) user_login_final_validate


user_login_final_validate() is here: http://api.drupal.org/api/drupal/modules--user--user.module/function/user_login_final_validate

Here is the code for vtiger_portal_user_form_validate() and the authentication function that it calls:

function vtiger_portal_user_form_validate($form, &amp;$form_state) {
  if (!vtiger_portal_authenticate($form_state)) {
    // Not a portal user. Let the other validation handlers run.
  } else {
    global $user;
    if($user-&gt;uid) {
      dpm($user);
    }
  }
}

/**
 * Custom user authentication function
 */
function vtiger_portal_authenticate($form_state) {  
  $username = $form_state['input']['name'];
  $password = $form_state['input']['pass'];
  $testname = drupal_substr(drupal_strtolower($username),0,4);
  if ($testname == "dave") {
    user_external_login_register($username, 'vtiger_portal');
    return TRUE;
  } else {
    return FALSE;
  }
}


I'm Seeing the "Sorry, unrecognized username or password. Have you forgotten your password?" error and at the same time, being successfully logged in.  I have printed the $user object after calling user_external_login_register() and it shows that the uid is 9.

Can anyone help me figure out why I'm seeing an error from user_login_final_validate() when the user has obviously logged in successfully?

Update: I've found the root of the problem.

From the line 2121, user.module contains the following code.

// We are not limited by flood control, so try to authenticate.
// Set $form_state['uid'] as a flag for user_login_final_validate().
$form_state['uid'] = user_authenticate($form_state['values']['name'], $password);


user_login_authenticate_validate() sets $form_state['uid'] to FALSE so that later user_login_final_validate() sends it's error message.
The OP mistakenly pasted user_login_final_validate() from D6 instead of D7. In D7, you avoid that error message by simply setting $form_state['uid'] = [a number]. You do that from within your custom #validate callback. Once you have done that, user_login_final_validate() will not throw an error and your form submission proceeds and thus login proceeds.