{"record":{"id":"381c67f102279050","repo":"apache/hadoop","slug":"too-many-or-few-parameters-for-request-method","errorCode":null,"errorMessage":"Too many or few parameters for request. Method: [{}], Expected: 2, Actual: {}","messagePattern":"Too many or few parameters for request\\. Method: \\[(.+?)\\], Expected: 2, Actual: (.+?)","errorType":"validation","errorClass":"ServiceException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/ProtobufRpcEngine.java","lineNumber":221,"sourceCode":"     * <li>Exceptions from the server are wrapped in RemoteException and are\n     * set as cause in ServiceException</li>\n     * </ol>\n     * \n     * Note that the client calling protobuf RPC methods, must handle\n     * ServiceException by getting the cause from the ServiceException. If the\n     * cause is RemoteException, then unwrap it to get the exception thrown by\n     * the server.\n     */\n    @Override\n    public Message invoke(Object proxy, final Method method, Object[] args)\n        throws ServiceException {\n      long startTime = 0;\n      if (LOG.isDebugEnabled()) {\n        startTime = Time.monotonicNow();\n      }\n      \n      if (args.length != 2) { // RpcController + Message\n        throw new ServiceException(\n            \"Too many or few parameters for request. Method: [\"\n            + method.getName() + \"]\" + \", Expected: 2, Actual: \"\n            + args.length);\n      }\n      if (args[1] == null) {\n        throw new ServiceException(\"null param while calling Method: [\"\n            + method.getName() + \"]\");\n      }\n\n      // if Tracing is on then start a new span for this rpc.\n      // guard it in the if statement to make sure there isn't\n      // any extra string manipulation.\n      Tracer tracer = Tracer.curThreadTracer();\n      TraceScope traceScope = null;\n      if (tracer != null) {\n        traceScope = tracer.newScope(RpcClientUtil.methodToTraceString(method));\n      }\n","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/ProtobufRpcEngine.java#L203-L239","documentation":"ProtobufRpcEngine's InvocationHandler (the layer under a java.lang.reflect proxy created by RPC.getProxy for protobuf protocols) insists every protocol method has exactly two arguments: an RpcController plus one request Message. If args.length != 2 it throws ServiceException immediately, before any network I/O. Hitting it almost always means a non-standard method was invoked through the protobuf proxy.","triggerScenarios":"Calling a default or static helper method that was added to the protocol interface with a different arity through the RPC proxy; invoking a translator-style method (extra arg) directly on the proxy object; reflective tooling (Mockito, AOP wrappers) calling proxy methods with modified argument arrays.","commonSituations":"Extending a *Protocol interface with convenience methods and calling them via the PB proxy instead of the translator; hand-rolled reflection over Hadoop proxies; version skew where a newer interface adds non-RPC methods.","solutions":["Keep the protobuf protocol interface to exactly (RpcController, RequestMessage) methods; put helper/extra-arity methods in a separate interface or the client-side translator class.","Invoke utility methods on the translator (e.g., ClientNamenodeProtocolTranslatorPB), not on the raw PB proxy.","If you must call via reflection, assert the 2-arg shape first."],"exampleFix":"// before\npublic interface MyProtocolPB {\n  RpcController getController();                       // 0 args -> ServiceException\n  MyResponseProto execute(RpcController c, MyRequestProto req);\n}\nMyProtocolPB proxy = RPC.getProxy(MyProtocolPB.class, version, addr, conf);\nproxy.getController();\n\n// after\npublic interface MyProtocolPB { // wire interface stays 2-arg only\n  MyResponseProto execute(RpcController c, MyRequestProto req);\n}\npublic class MyProtocolTranslatorPB { // helpers live here\n  private final MyProtocolPB proxy;\n  RpcController getController() { return null; }\n MyResponseProto execute(MyRequestProto req) { return proxy.execute(null, req); }\n}","handlingStrategy":"validation","validationCode":"for (Method m : protoInterface.getMethods()) {\n  if (!(m.getParameterCount() == 2\n        && RpcController.class.isAssignableFrom(m.getParameterTypes()[0])\n        && Message.class.isAssignableFrom(m.getParameterTypes()[1]))) {\n    throw new IllegalStateException(\"Non-RPC method on PB interface: \" + m);\n  }\n}","typeGuard":"static boolean isProtobufRpcMethod(Method m) {\n  Class<?>[] p = m.getParameterTypes();\n  return p.length == 2\n      && RpcController.class.isAssignableFrom(p[0])\n      && Message.class.isAssignableFrom(p[1])\n      && Message.class.isAssignableFrom(m.getReturnType());\n}","tryCatchPattern":null,"preventionTips":["Keep *ProtocolPB interfaces free of helper/default methods; put them in translators.","Run the signature lint above as a unit test over your protocol interfaces.","Call user-facing APIs on the translator, never on the raw PB proxy."],"tags":["hadoop","ipc","rpc","protobuf","proxy","reflection"],"backgroundTag":"rpc-method-signature-mismatch","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}