apache/hadoop · critical · AccessControlException
Can't retrieve username from tokenIdentifier.
Error message
Can't retrieve username from tokenIdentifier.
What it means
On a TOKEN-authenticated connection, getAuthorizedUgi resolves the SASL identity through SaslRpcServer.getIdentifier to a TokenIdentifier and asks it for its UserGroupInformation; if tokenId.getUser() returns null, authorization fails with AccessControlException("Can't retrieve username from tokenIdentifier."). The token parsed, but its identifier could not name an owning user — a server-side auth failure that kills the connection.
Source
Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Server.java:2235
/* Decrement the outstanding RPC count */
private void decRpcCount() {
rpcCount.decrementAndGet();
}
/* Increment the outstanding RPC count */
private void incRpcCount() {
rpcCount.incrementAndGet();
}
private UserGroupInformation getAuthorizedUgi(String authorizedId)
throws InvalidToken, AccessControlException {
if (authMethod == AuthMethod.TOKEN) {
TokenIdentifier tokenId = SaslRpcServer.getIdentifier(authorizedId,
secretManager);
UserGroupInformation ugi = tokenId.getUser();
if (ugi == null) {
throw new AccessControlException(
"Can't retrieve username from tokenIdentifier.");
}
ugi.addTokenIdentifier(tokenId);
return ugi;
} else {
return UserGroupInformation.createRemoteUser(authorizedId, authMethod);
}
}
private void saslReadAndProcess(RpcWritable.Buffer buffer) throws
RpcServerException, IOException, InterruptedException {
final RpcSaslProto saslMessage =
getMessage(RpcSaslProto.getDefaultInstance(), buffer);
switch (saslMessage.getState()) {
case WRAP: {
if (!saslContextEstablished || !useWrap) {
throw new FatalRpcServerException(
RpcErrorCodeProto.FATAL_INVALID_RPC_HEADER,View on GitHub (pinned to 2add963021)
Solutions
- If you own the TokenIdentifier class, implement getUser() to return the owning UserGroupInformation — never null.
- Verify the token's kind maps to the intended identifier class in SaslRpcServer's token identifier registry so it decodes with full owner info.
- As a client, obtain a fresh delegation token from the target service — the old one decodes to an identifier without a user.
Example fix
// before
public class MyTokenIdentifier extends AbstractDelegationTokenIdentifier {
@Override
public UserGroupInformation getUser() {
return null; // triggers AccessControlException on the server
}
}
// after
@Override
public UserGroupInformation getUser() {
return UserGroupInformation.createRemoteUser(getOwner().toString());
} Defensive patterns
Strategy: try-catch
Try / catch
Catch AccessControlException on the RPC/connection layer, treat it as a non-retryable authentication failure, and re-authenticate: fetch a fresh delegation token from the target service (or re-login for Kerberos) before reconnecting.
Prevention
- Custom TokenIdentifier implementations must always return a UGI from getUser().
- Register every token kind with its proper identifier class.
- Do not carry delegation tokens across service versions; mint them from the target service.
When it happens
Trigger: A delegation token whose TokenIdentifier.getUser() returns null: custom TokenIdentifier implementations that never return a user, token kinds mapped to an identifier class without owner information, or tokens minted by a mismatched/older service version so the identifier decodes without an owner.
Common situations: Custom authentication plugins introducing new token kinds; tokens carried across service versions; proxy-user setups where the identifier lost the owner field; WebHDFS/HTTP flows surfacing this as a 401/connection failure.
Related errors
- ${method} authentication is not enabled. Available:${enable
- Server asks us to fall back to SIMPLE auth, but this client
- FATAL_INVALID_RPC_HEADER
- Client already attempted negotiation
- Client mechanism is malformed
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/cfdfeda105943e27.
Report an issue: GitHub.