apache/hadoop · error · KerberosAuthException

loginUserFromKeyTab must be done first

Error message

loginUserFromKeyTab must be done first

What it means

The keytab logout path (logoutUserFromKeytab) requires a live HadoopLoginContext and a keytab file recorded on the UGI. If the UGI has Kerberos credentials but login==null or keytab==null - i.e., it never logged in from a keytab - it throws KerberosAuthException(MUST_FIRST_LOGIN_FROM_KEYTAB).

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/UserGroupInformation.java:1172

   * @throws KerberosAuthException if a failure occurred in logout,
   * or if the user did not log in by invoking loginUserFromKeyTab() before.
   */
  @InterfaceAudience.Public
  @InterfaceStability.Evolving
  public void logoutUserFromKeytab() throws IOException {
    if (!hasKerberosCredentials()) {
      return;
    }

    // Shutdown the background task performing login renewal.
    if (getKerberosLoginRenewalExecutor().isPresent()) {
      getKerberosLoginRenewalExecutor().get().shutdownNow();
    }

    HadoopLoginContext login = getLogin();
    String keytabFile = getKeytab();
    if (login == null || keytabFile == null) {
      throw new KerberosAuthException(MUST_FIRST_LOGIN_FROM_KEYTAB);
    }

    try {
      LOG.debug("Initiating logout for {}", getUserName());
      // hadoop login context internally locks credentials.
      login.logout();
    } catch (LoginException le) {
      KerberosAuthException kae = new KerberosAuthException(LOGOUT_FAILURE, le);
      kae.setUser(user.toString());
      kae.setKeytabFile(keytabFile);
      throw kae;
    }

    LOG.info("Logout successful for user " + getUserName()
        + " using keytab file " + keytabFile);
  }
  
  /**

View on GitHub (pinned to 2add963021)

Solutions

  1. Only call logoutUserFromKeytab on UGI instances returned by loginUserFromKeytab(principal, keytabFile)
  2. Branch on ugi.isFromKeytab() (or UserGroupInformation.isLoginKeytabBased()) before logging out
  3. For ticket-cache sessions, let the TGT expire or kdestroy manually - there is no keytab logout

Example fix

// before
ugi.logoutUserFromKeytab(); // fails for ticket-cache UGIs
// after
if (ugi.isFromKeytab()) {
  ugi.logoutUserFromKeytab();
}
Defensive patterns

Strategy: validation

Validate before calling

if (!ugi.isFromKeytab()) {
  // ticket-cache / external subjects cannot be keytab-logged-out
  return;
}

Type guard

static boolean isKeytabLogoutable(UserGroupInformation ugi) {
  return ugi.isFromKeytab() && ugi.hasKerberosCredentials();
}

Try / catch

try {
  ugi.logoutUserFromKeytab();
} catch (KerberosAuthException e) {
  LOG.warn("skip keytab logout for non-keytab UGI {}", ugi, e);
}

Prevention

When it happens

Trigger: Calling ugi.logoutUserFromKeytab() on a UGI obtained via loginUserFromTicketCache, getUGIFromSubject, or getLoginUser under ticket-cache mode; also UGI instances reconstructed after serialization, whose login context did not survive.

Common situations: Generic cleanup/shutdown code assuming every Kerberos UGI came from a keytab; daemons mixing ticket-cache and keytab logins; job/task UGI copies.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/f03ba3ab950c0879. Report an issue: GitHub.