{"record":{"id":"d50da5640211c93e","repo":"apache/hadoop","slug":"param-op-must-be-specified","errorCode":null,"errorMessage":"Param op must be specified.","messagePattern":"Param op must be specified\\.","errorType":"http","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/tools/offlineImageViewer/FSImageHandler.java","lineNumber":93,"sourceCode":"\n  @Override\n  public void channelRead0(ChannelHandlerContext ctx, HttpRequest request)\n      throws Exception {\n    if (request.method() != HttpMethod.GET) {\n      DefaultHttpResponse resp = new DefaultHttpResponse(HTTP_1_1,\n          METHOD_NOT_ALLOWED);\n      resp.headers().set(CONNECTION, CLOSE);\n      ctx.write(resp).addListener(ChannelFutureListener.CLOSE);\n      return;\n    }\n\n    QueryStringDecoder decoder = new QueryStringDecoder(request.uri());\n    // check path. throw exception if path doesn't start with WEBHDFS_PREFIX\n    String path = getPath(decoder);\n    final String op = getOp(decoder);\n    // check null op\n    if (op == null) {\n      throw new IllegalArgumentException(\"Param op must be specified.\");\n    }\n\n    final String content;\n    switch (op) {\n    case \"GETFILESTATUS\":\n      content = image.getFileStatus(path);\n      break;\n    case \"LISTSTATUS\":\n      content = image.listStatus(path);\n      break;\n    case \"GETACLSTATUS\":\n      content = image.getAclStatus(path);\n      break;\n    case \"GETXATTRS\":\n      List<String> names = getXattrNames(decoder);\n      String encoder = getEncoder(decoder);\n      content = image.getXAttrs(path, names, encoder);\n      break;","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/tools/offlineImageViewer/FSImageHandler.java#L75-L111","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Add the operation parameter, quoted for the shell: curl 'http://host:port/webhdfs/v1/user/foo?op=GETFILESTATUS'.","Use a WebHDFS-aware client (hdfs dfs -ls webhdfs://host:port/user/foo) which always sends op.","For health checks, treat 400-without-op as 'server is up', or test TCP connectivity instead of HTTP semantics."],"exampleFix":"# before\ncurl http://localhost:5978/webhdfs/v1/user/foo\n# -> 400 Param op must be specified.\n\n# after\ncurl 'http://localhost:5978/webhdfs/v1/user/foo?op=GETFILESTATUS'","handlingStrategy":"validation","validationCode":"import io.netty.handler.codec.http.QueryStringDecoder;\n\nQueryStringDecoder d = new QueryStringDecoder(uri);\nif (!d.parameters().containsKey(\"op\")) {\n  throw new IllegalArgumentException(\"Missing op; one of GETFILESTATUS, LISTSTATUS, GETACLSTATUS, GETXATTRS, LISTXATTRS, GETCONTENTSUMMARY\");\n}","typeGuard":"private static final Set<String> SUPPORTED_OPS = new HashSet<>(Arrays.asList(\n    \"GETFILESTATUS\", \"LISTSTATUS\", \"GETACLSTATUS\",\n    \"GETXATTRS\", \"LISTXATTRS\", \"GETCONTENTSUMMARY\"));\n\nstatic boolean isSupportedOp(String op) {\n  return op != null && SUPPORTED_OPS.contains(op.toUpperCase(Locale.ROOT));\n}","tryCatchPattern":"// server side this is already handled: IllegalArgumentException -> HTTP 400 JSON body\n// client side: check the response status and the RemoteException message\nif (resp.getStatusLine().getStatusCode() == 400) {\n  // re-read the JSON body: it contains \"Param op must be specified.\"\n}","preventionTips":["Always quote full URLs with the query string in shells.","Prefer the webhdfs:// client, which fills in op automatically.","Health probes should test TCP connect, not expect 200 from a bare GET."],"tags":["hdfs","offline-image-viewer","webhdfs","http","query-parameter"],"backgroundTag":"missing-query-parameter","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}