apache/hadoop · error · IOException

Only Namenode, Secondary Namenode, and administrators may ac

Error message

Only Namenode, Secondary Namenode, and administrators may access this servlet

What it means

ImageServlet.validateRequest throws this when Kerberos security is enabled and the authenticated principal fetching an image or edit log is not recognized by isValidRequestor, which admits the NameNode, Secondary/Standby NameNode principals and configured administrators (dfs.cluster.administrators). It is the authorization guard for the checkpoint-transfer endpoint and answers 403 Forbidden before any namespace data is sent. The accompanying LOG.warn names the rejected principal and remote host.

Source

Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/ImageServlet.java:243

      response.getOutputStream().close();
    }
  }

  private void validateRequest(ServletContext context, Configuration conf,
      HttpServletRequest request, HttpServletResponse response,
      FSImage nnImage, String theirStorageInfoString) throws IOException {

    if (UserGroupInformation.isSecurityEnabled()
        && !isValidRequestor(context, request.getUserPrincipal().getName(),
            conf)) {
      String errorMsg = "Only Namenode, Secondary Namenode, and administrators may access "
          + "this servlet";
      sendError(response, HttpServletResponse.SC_FORBIDDEN, errorMsg);
      LOG.warn("Received non-NN/SNN/administrator request for image or edits from "
          + request.getUserPrincipal().getName()
          + " at "
          + request.getRemoteHost());
      throw new IOException(errorMsg);
    }

    String myStorageInfoString = nnImage.getStorage().toColonSeparatedString();
    if (theirStorageInfoString != null
        && !myStorageInfoString.equals(theirStorageInfoString)) {
      String errorMsg = "This namenode has storage info " + myStorageInfoString
          + " but the secondary expected " + theirStorageInfoString;
      sendError(response, HttpServletResponse.SC_FORBIDDEN, errorMsg);
      LOG.warn("Received an invalid request file transfer request "
          + "from a secondary with storage info " + theirStorageInfoString);
      throw new IOException(errorMsg);
    }
  }

  public static void setFileNameHeaders(HttpServletResponse response,
      File file) {
    response.setHeader(CONTENT_DISPOSITION, "attachment; filename=" +
        file.getName());

View on GitHub (pinned to 2add963021)

Solutions

  1. Take the rejected principal from the NN log line 'Received non-NN/SNN/administrator request ... at HOST' and compare it with the principal your 2NN/Standby actually authenticates with (klist -kt).
  2. Make the Secondary/Standby run with the expected Kerberos principal and keytab (dfs.namenode.keytab.* and dfs.namenode.secondary.* / http_principal settings).
  3. Add legitimate human operators or groups to dfs.cluster.administrators if they need to fetch images.
  4. If realm mapping differs, fix krb5.conf domain_realm or use fully-qualified principal names in the ACL.
Defensive patterns

Strategy: validation

Validate before calling

// Before starting the Secondary, prove the identity it will present to the servlet
UserGroupInformation.loginUserFromKeytab(principal, keytabPath);
String me = UserGroupInformation.getCurrentUser().getUserName();
String admins = conf.get("dfs.cluster.administrators", "*");
boolean adminOk = admins.equals("*") || admins.contains(me);
if (!adminOk && !me.startsWith("nn/") && !me.startsWith("nn_")) {
  throw new IllegalStateException("Principal " + me + " will be 403-rejected by ImageServlet; fix keytab/admins ACL");
}

Try / catch

try {
  TransferFsImage.getFileClient(...); // any image fetch
} catch (IOException e) {
  if (e.getMessage() != null && e.getMessage().contains("Only Namenode, Secondary Namenode")) {
    throw new ConfigurationException("2NN principal not authorized for image servlet - check keytab and dfs.cluster.administrators", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: UserGroupInformation.isSecurityEnabled() is true and request.getUserPrincipal() is a principal outside the allowed set: a 2NN/Standby running with a different or missing Kerberos keytab/principal, a cross-realm principal whose string does not match the configured pattern, or an operator fetching with a non-admin kinit.

Common situations: Secondary NameNode principal not covered by dfs.namenode.secondary kerberos principal patterns; Standby configured with its own principal while the servlet only accepts the NN pattern; dfs.cluster.administrators ACL stale after team changes; missing cross-realm trust so the principal string differs from what was configured.

Related errors


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