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

  1. Make handleRefresh return a RefreshResponse on every path — failures as new RefreshResponse(-1, "reason").
  2. Return a success response (e.g., RefreshResponse.success(...)) as the default last line so no path can fall through to null.
  3. 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

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


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/383591782deded57. Report an issue: GitHub.