{"record":{"id":"d414cd5dd1085d48","repo":"apache/hadoop","slug":"credential-already-exists-in","errorCode":null,"errorMessage":"Credential {} already exists in {}","messagePattern":"Credential (.+?) already exists in (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/alias/UserProvider.java","lineNumber":69,"sourceCode":"    return true;\n  }\n\n  @Override\n  public synchronized CredentialEntry getCredentialEntry(String alias) {\n    byte[] bytes = credentials.getSecretKey(new Text(alias));\n    if (bytes == null) {\n      return null;\n    }\n    return new CredentialEntry(\n        alias, new String(bytes, StandardCharsets.UTF_8).toCharArray());\n  }\n\n  @Override\n  public synchronized CredentialEntry createCredentialEntry(String name, char[] credential) \n      throws IOException {\n    Text nameT = new Text(name);\n    if (credentials.getSecretKey(nameT) != null) {\n      throw new IOException(\"Credential \" + name + \n          \" already exists in \" + this);\n    }\n    credentials.addSecretKey(new Text(name), \n        new String(credential).getBytes(StandardCharsets.UTF_8));\n    return new CredentialEntry(name, credential);\n  }\n\n  @Override\n  public synchronized void deleteCredentialEntry(String name) throws IOException {\n    byte[] cred = credentials.getSecretKey(new Text(name));\n    if (cred != null) {\n      credentials.removeSecretKey(new Text(name));\n    }\n    else {\n      throw new IOException(\"Credential \" + name + \n          \" does not exist in \" + this);\n    }\n  }","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/alias/UserProvider.java#L51-L87","documentation":"UserProvider (the in-memory user:// provider backed by the UGI Credentials object) rejects createCredentialEntry() when the alias already has a secret key stored. Unlike file-backed stores, this state lives per-JVM/session, and entries often get there implicitly when credentials are copied from other providers into the job's Credentials.","triggerScenarios":"Calling userProvider.createCredentialEntry(name, cred) twice; the alias was already added via credentials.addSecretKey() or copied from a jceks provider into the same UGI Credentials; re-running bootstrap code in one session.","commonSituations":"Retrieving all providers via CredentialProviderFactory.getProviders() (user:// is always first) and trying to create into it without checking; tests that create fixtures repeatedly; migration code that copies then re-creates.","solutions":["Check first: provider.getCredentialEntry(name) != null -> delete or skip","For overwrite semantics go to the underlying object: ugi.getCredentials().addSecretKey(new Text(name), bytes) (replaces silently)","Filter providers by scheme - skip user:// when your intent is persistent storage, use jceks/localjceks"],"exampleFix":"// before\nfor (CredentialProvider p : CredentialProviderFactory.getProviders(conf)) {\n  p.createCredentialEntry(name, secret);   // user:// already has it -> IOException\n}\n\n// after\nCredentialEntry existing = p.getCredentialEntry(name);\nif (existing == null) {\n  p.createCredentialEntry(name, secret);\n}","handlingStrategy":"validation","validationCode":"// Skip or delete before create on the user:// provider\nif (provider instanceof UserProvider) {\n  if (provider.getCredentialEntry(name) != null) {\n    provider.deleteCredentialEntry(name);   // or skip if present\n  }\n}\nprovider.createCredentialEntry(name, credential);","typeGuard":"boolean isUserProvider(CredentialProvider p) {\n  return p instanceof org.apache.hadoop.security.alias.UserProvider;\n}","tryCatchPattern":"try {\n  provider.createCredentialEntry(name, credential);\n} catch (IOException ex) {\n  if (ex.getMessage() != null && ex.getMessage().contains(\"already exists\")) {\n    ugi.getCredentials().addSecretKey(new Text(name),\n        new String(credential).getBytes(StandardCharsets.UTF_8)); // overwrite semantics\n  } else { throw ex; }\n}","preventionTips":["getProviders() always returns user:// first - filter by scheme before writing","Treat the UGI Credentials object as the overwrite path; provider.create is insert-only","In tests, clear state (new UGI / fresh Credentials) between fixtures"],"tags":["hadoop","credential-provider","user-provider","alias-exists","in-memory"],"backgroundTag":"duplicate-keystore-alias","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}