{"record":{"id":"f03ba3ab950c0879","repo":"apache/hadoop","slug":"loginuserfromkeytab-must-be-done-first","errorCode":null,"errorMessage":"loginUserFromKeyTab must be done first","messagePattern":"loginUserFromKeyTab must be done first","errorType":"exception","errorClass":"KerberosAuthException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/UserGroupInformation.java","lineNumber":1172,"sourceCode":"   * @throws KerberosAuthException if a failure occurred in logout,\n   * or if the user did not log in by invoking loginUserFromKeyTab() before.\n   */\n  @InterfaceAudience.Public\n  @InterfaceStability.Evolving\n  public void logoutUserFromKeytab() throws IOException {\n    if (!hasKerberosCredentials()) {\n      return;\n    }\n\n    // Shutdown the background task performing login renewal.\n    if (getKerberosLoginRenewalExecutor().isPresent()) {\n      getKerberosLoginRenewalExecutor().get().shutdownNow();\n    }\n\n    HadoopLoginContext login = getLogin();\n    String keytabFile = getKeytab();\n    if (login == null || keytabFile == null) {\n      throw new KerberosAuthException(MUST_FIRST_LOGIN_FROM_KEYTAB);\n    }\n\n    try {\n      LOG.debug(\"Initiating logout for {}\", getUserName());\n      // hadoop login context internally locks credentials.\n      login.logout();\n    } catch (LoginException le) {\n      KerberosAuthException kae = new KerberosAuthException(LOGOUT_FAILURE, le);\n      kae.setUser(user.toString());\n      kae.setKeytabFile(keytabFile);\n      throw kae;\n    }\n\n    LOG.info(\"Logout successful for user \" + getUserName()\n        + \" using keytab file \" + keytabFile);\n  }\n  \n  /**","sourceCodeStart":1154,"sourceCodeEnd":1190,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/UserGroupInformation.java#L1154-L1190","documentation":"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).","triggerScenarios":"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.","commonSituations":"Generic cleanup/shutdown code assuming every Kerberos UGI came from a keytab; daemons mixing ticket-cache and keytab logins; job/task UGI copies.","solutions":["Only call logoutUserFromKeytab on UGI instances returned by loginUserFromKeytab(principal, keytabFile)","Branch on ugi.isFromKeytab() (or UserGroupInformation.isLoginKeytabBased()) before logging out","For ticket-cache sessions, let the TGT expire or kdestroy manually - there is no keytab logout"],"exampleFix":"// before\nugi.logoutUserFromKeytab(); // fails for ticket-cache UGIs\n// after\nif (ugi.isFromKeytab()) {\n  ugi.logoutUserFromKeytab();\n}","handlingStrategy":"validation","validationCode":"if (!ugi.isFromKeytab()) {\n  // ticket-cache / external subjects cannot be keytab-logged-out\n  return;\n}","typeGuard":"static boolean isKeytabLogoutable(UserGroupInformation ugi) {\n  return ugi.isFromKeytab() && ugi.hasKerberosCredentials();\n}","tryCatchPattern":"try {\n  ugi.logoutUserFromKeytab();\n} catch (KerberosAuthException e) {\n  LOG.warn(\"skip keytab logout for non-keytab UGI {}\", ugi, e);\n}","preventionTips":["Record how each UGI was created (keytab vs ticket vs subject) alongside the reference","Gate logout paths on ugi.isFromKeytab()","Do not serialize/copy UGIs and expect login state to survive"],"tags":["hadoop","kerberos","ugi","keytab","logout"],"backgroundTag":"operation-before-login","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}