apache/hadoop · error · NullPointerException
Handler returned null.
Error message
Handler returned null.
What it means
RefreshRegistry.dispatch requires every RefreshHandler.handleRefresh to return a non-null RefreshResponse. A null return raises NullPointerException("Handler returned null.") inside the per-handler loop, which the surrounding catch immediately converts into a RefreshResponse(-1, localizedMessage) — the admin client sees a failed refresh carrying this message, and the server stays up. It always indicates a bug in the handler implementation.
Source
Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/RefreshRegistry.java:116
String msg = "Identifier '" + identifier +
"' does not exist in RefreshRegistry. Valid options are: " +
Joiner.on(", ").join(handlerTable.keySet());
throw new IllegalArgumentException(msg);
}
ArrayList<RefreshResponse> responses =
new ArrayList<RefreshResponse>(handlers.size());
// Dispatch to each handler and store response
for(RefreshHandler handler : handlers) {
RefreshResponse response;
// Run the handler
try {
response = handler.handleRefresh(identifier, args);
if (response == null) {
throw new NullPointerException("Handler returned null.");
}
LOG.info(handlerName(handler) + " responds to '" + identifier +
"', says: '" + response.getMessage() + "', returns " +
response.getReturnCode());
} catch (Exception e) {
response = new RefreshResponse(-1, e.getLocalizedMessage());
}
response.setSenderName(handlerName(handler));
responses.add(response);
}
return responses;
}
private String handlerName(RefreshHandler h) {
return h.getClass().getName() + '@' + Integer.toHexString(h.hashCode());View on GitHub (pinned to 2add963021)
Solutions
- Make handleRefresh return a RefreshResponse on every path — failures as new RefreshResponse(-1, "reason").
- Return a success response (e.g., RefreshResponse.success(...)) as the default last line so no path can fall through to null.
- Add unit tests covering every argument branch of handleRefresh to catch null paths before deployment.
Example fix
// before
@Override
public RefreshResponse handleRefresh(String identifier, String[] args) {
if (args.length != 1) {
return null; // becomes RefreshResponse(-1, "Handler returned null.")
}
return doRefresh(args[0]);
}
// after
@Override
public RefreshResponse handleRefresh(String identifier, String[] args) {
if (args.length != 1) {
return new RefreshResponse(-1, "expected exactly 1 argument");
}
return doRefresh(args[0]);
} Defensive patterns
Strategy: validation
Validate before calling
// defensive wrapper when invoking handlers you do not own
RefreshResponse r;
try {
r = handler.handleRefresh(id, args);
} catch (Exception e) {
r = new RefreshResponse(-1, e.getLocalizedMessage());
}
if (r == null) {
r = new RefreshResponse(-1, "handler returned null");
} Prevention
- Never return null from handleRefresh — every branch returns a RefreshResponse.
- End the method with a default success response so no path falls through.
- Treat a '-1 Handler returned null.' response as a handler bug to fix, not an operational condition.
When it happens
Trigger: A RefreshHandler implementation with a code path that returns null: an early-exit branch for unrecognized arguments, a missing final return after refactoring, or a third-party plugin registered as a refreshable.
Common situations: Custom refresh handlers where one branch forgets to build a response; copied handler skeletons where the error path is a stub 'return null'; refactors of handleRefresh that drop the trailing return statement.
Related errors
- Identifier cannot be null
- Identifier '${identifier}' does not exist in RefreshRegistry
- Unable to refresh queues because queue-hierarchy changed. Re
- Request must contain identifier
- Refresh not supported by " + getClass()
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/383591782deded57.
Report an issue: GitHub.