apache/hadoop · error · UnsupportedCallbackException
Unsupported callback:
Error message
Unsupported callback:
What it means
Hadoop's SASL DIGEST-MD5 server callback machinery supports pluggable callback handlers via hadoop.security.sasl.CustomizedCallbackHandler.class. When no custom handler is configured (or the configured class could not be instantiated), the built-in DefaultHandler is used, and it rejects every callback it is handed. The exception names the exact callback class that was unsupported, which tells you which SASL callback type arrived. Empty callback lists pass through silently; any non-empty list throws.
Source
Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/CustomizedCallbackHandler.java:90
return cached != null ? cached : getSynchronously(key, conf);
}
public static synchronized void clear() {
MAP.clear();
}
private Cache() { }
}
class DefaultHandler implements CustomizedCallbackHandler {
private static final DefaultHandler INSTANCE = new DefaultHandler();
@Override
public void handleCallbacks(List<Callback> callbacks, String username, char[] password)
throws UnsupportedCallbackException {
if (!callbacks.isEmpty()) {
final Callback cb = callbacks.get(0);
throw new UnsupportedCallbackException(callbacks.get(0),
"Unsupported callback: " + (cb == null ? null : cb.getClass()));
}
}
}
static CustomizedCallbackHandler delegate(Object delegated) {
final String methodName = "handleCallbacks";
final Class<?> clazz = delegated.getClass();
final Method method;
try {
method = clazz.getMethod(methodName, List.class, String.class, char[].class);
} catch (NoSuchMethodException e) {
throw new IllegalStateException("Failed to get method " + methodName + " from " + clazz, e);
}
return (callbacks, name, password) -> {
try {
method.invoke(delegated, callbacks, name, password);View on GitHub (pinned to 2add963021)
Solutions
- Set hadoop.security.sasl.CustomizedCallbackHandler.class in core-site.xml to a class that implements CustomizedCallbackHandler (or exposes handleCallbacks(List<Callback>, String, char[])) and restart the service
- If you configured a class already, check the server log for 'Failed to create a new instance of ... fallback to DefaultHandler' — fix the NoClassDefFound/constructor access issue so your class actually loads
- Ensure your handler actually consumes the callback type shown in the message (the exception prints cb.getClass()) instead of rethrowing
- If you never intended custom callbacks, investigate why the client is negotiating an auth path that requires them (e.g. DIGEST-MD5 with tokens) and switch to KERBEROS or SIMPLE as appropriate
Example fix
# before (core-site.xml): handler missing, DefaultHandler throws
# after
<property>
<name>hadoop.security.sasl.CustomizedCallbackHandler.class</name>
<value>com.mycompany.MyDigestCallbackHandler</value>
</property>
// handler must implement the interface or expose the reflective method
public class MyDigestCallbackHandler
implements CustomizedCallbackHandler {
@Override
public void handleCallbacks(List<Callback> callbacks, String username,
char[] password) throws UnsupportedCallbackException {
for (Callback cb : callbacks) {
if (cb instanceof AuthorizeCallback) {
((AuthorizeCallback) cb).setAuthorized(true);
} else {
throw new UnsupportedCallbackException(cb);
}
}
}
} Defensive patterns
Strategy: validation
Validate before calling
// before handing callbacks to the handler
CustomizedCallbackHandler h =
CustomizedCallbackHandler.get(
CommonConfigurationKeysPublic.HADOOP_SECURITY_SASL_CUSTOMIZEDCALLBACKHANDLER_CLASS_KEY,
conf);
if (h instanceof CustomizedCallbackHandler.DefaultHandler
&& !callbacks.isEmpty()) {
// DefaultHandler will throw UnsupportedCallbackException
LOG.warn("No customized callback handler configured; "
+ "DIGEST-MD5 callbacks of type " + callbacks.get(0).getClass()
+ " will be rejected");
} Try / catch
try {
handler.handleCallbacks(callbacks, user, password);
} catch (UnsupportedCallbackException e) {
// e.getCallback() names the offending callback; log and abort the SASL step
LOG.error("Callback rejected: {}", e.getCallback().getClass(), e);
throw e;
} Prevention
- Configure hadoop.security.sasl.CustomizedCallbackHandler.class whenever token-based DIGEST-MD5 is used with non-standard callbacks
- Watch startup logs for 'Failed to create a new instance of ... fallback to DefaultHandler' — silent fallback is the usual precursor
- Write a smoke test that calls handleCallbacks with each callback type your handshake produces
When it happens
Trigger: A SASL handshake reaches SaslDigestCallbackHandler (e.g. a TokenIdentifier-based DIGEST-MD5 exchange in SaslRpcServer) and dispatches callbacks (NameCallback/PasswordCallback/AuthorizeCallback) to CustomizedCallbackHandler.get(...) while hadoop.security.sasl.CustomizedCallbackHandler.class is unset, set to an empty value, or points at a class whose instantiation failed (the cache silently falls back to DefaultHandler with only a WARN log).
Common situations: Clusters running token-based (DIGEST-MD5) authentication where an integration expects a custom handler to answer callbacks but the key was omitted from the server's core-site.xml; typos in the class name causing instantiation failure and silent fallback; upgrading Hadoop versions where the property name changed.
Related errors
- Server asks us to fall back to SIMPLE auth, but this client
- Failed to get method
- Failed to invoke
- Missing keyfile property ('%s') for authentication type '%s'
- Unknown authentication type: %s
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/8c9b0396bfe27239.
Report an issue: GitHub.