apache/hadoop · error · IOException
Credential {} already exists in {}
Error message
Credential {} already exists in {} What it means
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.
Source
Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/alias/UserProvider.java:69
return true;
}
@Override
public synchronized CredentialEntry getCredentialEntry(String alias) {
byte[] bytes = credentials.getSecretKey(new Text(alias));
if (bytes == null) {
return null;
}
return new CredentialEntry(
alias, new String(bytes, StandardCharsets.UTF_8).toCharArray());
}
@Override
public synchronized CredentialEntry createCredentialEntry(String name, char[] credential)
throws IOException {
Text nameT = new Text(name);
if (credentials.getSecretKey(nameT) != null) {
throw new IOException("Credential " + name +
" already exists in " + this);
}
credentials.addSecretKey(new Text(name),
new String(credential).getBytes(StandardCharsets.UTF_8));
return new CredentialEntry(name, credential);
}
@Override
public synchronized void deleteCredentialEntry(String name) throws IOException {
byte[] cred = credentials.getSecretKey(new Text(name));
if (cred != null) {
credentials.removeSecretKey(new Text(name));
}
else {
throw new IOException("Credential " + name +
" does not exist in " + this);
}
}View on GitHub (pinned to 2add963021)
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
Example fix
// before
for (CredentialProvider p : CredentialProviderFactory.getProviders(conf)) {
p.createCredentialEntry(name, secret); // user:// already has it -> IOException
}
// after
CredentialEntry existing = p.getCredentialEntry(name);
if (existing == null) {
p.createCredentialEntry(name, secret);
} Defensive patterns
Strategy: validation
Validate before calling
// Skip or delete before create on the user:// provider
if (provider instanceof UserProvider) {
if (provider.getCredentialEntry(name) != null) {
provider.deleteCredentialEntry(name); // or skip if present
}
}
provider.createCredentialEntry(name, credential); Type guard
boolean isUserProvider(CredentialProvider p) {
return p instanceof org.apache.hadoop.security.alias.UserProvider;
} Try / catch
try {
provider.createCredentialEntry(name, credential);
} catch (IOException ex) {
if (ex.getMessage() != null && ex.getMessage().contains("already exists")) {
ugi.getCredentials().addSecretKey(new Text(name),
new String(credential).getBytes(StandardCharsets.UTF_8)); // overwrite semantics
} else { throw ex; }
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Credential " + alias + " already exists in " + this
- Credential {} does not exist in {}
- Key ${name} already exists in ${this}
- Wrong key length. Required ${bitLength}, but got ${actualBit
- Can't get credential " + alias + " from " + getPathAsString(
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/d414cd5dd1085d48.
Report an issue: GitHub.