apache/hadoop · error · DelegationTokenIOException
Delegation token is wrong class; expected a token identifier
Error message
Delegation token is wrong class; expected a token identifier of type {expectedClass} but got {identifierClass} and kind {kind} What it means
When an S3A delegation token is bound, AbstractDelegationTokenBinding.convertTokenIdentifier requires the decoded token identifier's class to be exactly the binding's expected class (stricter than instanceof, rejecting subclasses too). A mismatch means a token issued by a different delegation-token binding is being fed to this one, so it throws DelegationTokenIOException with the TOKEN_WRONG_CLASS prefix showing expected vs actual class and the token kind.
Source
Thrown at hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/auth/delegation/AbstractDelegationTokenBinding.java:190
Optional<RoleModel.Policy> policy,
EncryptionSecrets encryptionSecrets,
Text renewer) throws IOException;
/**
* Verify that a token identifier is of a specific class.
* This will reject subclasses (i.e. it is stricter than
* {@code instanceof}, then cast it to that type.
* @param <T> type of S3A delegation ttoken identifier.
* @param identifier identifier to validate
* @param expectedClass class of the expected token identifier.
* @return token identifier.
* @throws DelegationTokenIOException If the wrong class was found.
*/
protected <T extends AbstractS3ATokenIdentifier> T convertTokenIdentifier(
final AbstractS3ATokenIdentifier identifier,
final Class<T> expectedClass) throws DelegationTokenIOException {
if (!identifier.getClass().equals(expectedClass)) {
throw new DelegationTokenIOException(
DelegationTokenIOException.TOKEN_WRONG_CLASS
+ "; expected a token identifier of type "
+ expectedClass
+ " but got "
+ identifier.getClass()
+ " and kind " + identifier.getKind());
}
return (T) identifier;
}
/**
* Deploy, returning the binding information.
* The base implementation calls
*
* @param retrievedIdentifier any identifier -null if deployed unbonded.
* @return binding information
* @throws IOException any failure.
*/View on GitHub (pinned to 2add963021)
Solutions
- Remove the stale token from the user's credentials (cancel it or start the job with fresh Credentials) so the filesystem rebinds or deploys unbonded
- Keep fs.s3a.delegation.token.binding identical on the issuing service and every consuming job
- Do not reuse persisted credential files across binding changes; re-fetch tokens after config changes
Example fix
# before: credentials file holds a token from the old binding hadoop --loglevel INFO fs -Dfs.s3a.delegation.token.binding=org.apache.hadoop.fs.s3a.auth.delegation.S3ATokenBinding -put local dest # after: drop stale tokens for the s3a service, then re-fetch # (cancel the old token with its renewer, or delete/recreate the credentials file) hadoop credential list hadoop fetchdt -rename s3a://bucket -- renewer
Defensive patterns
Strategy: type-guard
Validate before calling
Token<?> t = ugi.getCredentials().getToken(new Text("s3a://bucket"));
if (t != null && !expectedKind.equals(t.getKind())) {
ugi.getCredentials().removeToken(t.getService()); // drop token from wrong binding
LOG.warn("Dropped token kind {} (expected {})", t.getKind(), expectedKind);
} Type guard
static boolean tokenMatchesBinding(Token<?> t, Text expectedKind,
Class<? extends AbstractS3ATokenIdentifier> expectedClass) {
return t != null
&& expectedKind.equals(t.getKind())
&& expectedClass.equals(t.decodeIdentifier().getClass()); // exact class, like the binding
} Try / catch
try {
tokens.bindToDelegationToken(token);
} catch (DelegationTokenIOException e) {
if (e.getMessage().contains(DelegationTokenIOException.TOKEN_WRONG_CLASS)) {
// stale token from another binding: discard and rebind/deploy unbonded
credentials.removeToken(token.getService());
} else {
throw e;
}
} Prevention
- Keep fs.s3a.delegation.token.binding identical on issuers and consumers
- Do not persist credentials files across binding changes; re-fetch tokens
- Give each job fresh Credentials instead of sharing UGI credentials
When it happens
Trigger: The filesystem is configured with binding X (e.g. S3ATokenBinding expecting S3ATokenIdentifier) but the user's credentials contain a token for the same s3a:// URI whose identifier class belongs to binding Y (e.g. SessionTokenBinding's SessionTokenIdentifier). Occurs during bindToDelegationToken when deserializeToken converts the identifier.
Common situations: fs.s3a.delegation.token.binding changed between the run that fetched the token and the run that consumes it; tokens persisted in a credentials file across a binding change; mixed clusters where one service issues session tokens and another expects full-credential tokens.
Related errors
- Token mismatch: expected token for {service} of type {kind}
- {component}: No AWS credentials
- {component}: Invalid AWS credentials in {credentials} requir
- No URI in {this}
- Incompatible EncryptionSecrets version: {versionId}
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/7fc5009ecdba77f4.
Report an issue: GitHub.