apache/hadoop · error · IllegalArgumentException

Param op must be specified.

Error message

Param op must be specified.

What it means

FSImageHandler serves a read-only WebHDFS API over an fsimage (the offline image viewer web server). Every GET request must carry an op query parameter selecting the operation; getOp() returns null when it is absent and this IllegalArgumentException is thrown. exceptionCaught() converts it to HTTP 400 with a JSON RemoteException body.

Source

Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/tools/offlineImageViewer/FSImageHandler.java:93

  @Override
  public void channelRead0(ChannelHandlerContext ctx, HttpRequest request)
      throws Exception {
    if (request.method() != HttpMethod.GET) {
      DefaultHttpResponse resp = new DefaultHttpResponse(HTTP_1_1,
          METHOD_NOT_ALLOWED);
      resp.headers().set(CONNECTION, CLOSE);
      ctx.write(resp).addListener(ChannelFutureListener.CLOSE);
      return;
    }

    QueryStringDecoder decoder = new QueryStringDecoder(request.uri());
    // check path. throw exception if path doesn't start with WEBHDFS_PREFIX
    String path = getPath(decoder);
    final String op = getOp(decoder);
    // check null op
    if (op == null) {
      throw new IllegalArgumentException("Param op must be specified.");
    }

    final String content;
    switch (op) {
    case "GETFILESTATUS":
      content = image.getFileStatus(path);
      break;
    case "LISTSTATUS":
      content = image.listStatus(path);
      break;
    case "GETACLSTATUS":
      content = image.getAclStatus(path);
      break;
    case "GETXATTRS":
      List<String> names = getXattrNames(decoder);
      String encoder = getEncoder(decoder);
      content = image.getXAttrs(path, names, encoder);
      break;

View on GitHub (pinned to 2add963021)

Solutions

  1. Add the operation parameter, quoted for the shell: curl 'http://host:port/webhdfs/v1/user/foo?op=GETFILESTATUS'.
  2. Use a WebHDFS-aware client (hdfs dfs -ls webhdfs://host:port/user/foo) which always sends op.
  3. For health checks, treat 400-without-op as 'server is up', or test TCP connectivity instead of HTTP semantics.

Example fix

# before
curl http://localhost:5978/webhdfs/v1/user/foo
# -> 400 Param op must be specified.

# after
curl 'http://localhost:5978/webhdfs/v1/user/foo?op=GETFILESTATUS'
Defensive patterns

Strategy: validation

Validate before calling

import io.netty.handler.codec.http.QueryStringDecoder;

QueryStringDecoder d = new QueryStringDecoder(uri);
if (!d.parameters().containsKey("op")) {
  throw new IllegalArgumentException("Missing op; one of GETFILESTATUS, LISTSTATUS, GETACLSTATUS, GETXATTRS, LISTXATTRS, GETCONTENTSUMMARY");
}

Type guard

private static final Set<String> SUPPORTED_OPS = new HashSet<>(Arrays.asList(
    "GETFILESTATUS", "LISTSTATUS", "GETACLSTATUS",
    "GETXATTRS", "LISTXATTRS", "GETCONTENTSUMMARY"));

static boolean isSupportedOp(String op) {
  return op != null && SUPPORTED_OPS.contains(op.toUpperCase(Locale.ROOT));
}

Try / catch

// server side this is already handled: IllegalArgumentException -> HTTP 400 JSON body
// client side: check the response status and the RemoteException message
if (resp.getStatusLine().getStatusCode() == 400) {
  // re-read the JSON body: it contains "Param op must be specified."
}

Prevention

When it happens

Trigger: GET http://<oiv-host>:<port>/webhdfs/v1/<path> with no ?op=... parameter — e.g. opening the URL in a browser or curl-ing it bare. Proper WebHDFS clients always send op, so this indicates a hand-made or liveness-probe request.

Common situations: Users opening the viewer URL in a browser out of curiosity; monitoring scripts fetching the root URL as a health check; shell mangling that drops the query string (? or & swallowed unquoted).

Related errors


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