{"record":{"id":"d209a090db891f67","repo":"apache/hadoop","slug":"cannot-close-proxy-is-not-closeable-or-does-not","errorCode":null,"errorMessage":"Cannot close proxy - is not Closeable or does not provide closeable invocation handler ${proxyClass}","messagePattern":"Cannot close proxy - is not Closeable or does not provide closeable invocation handler (.+?)","errorType":"exception","errorClass":"HadoopIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/RPC.java","lineNumber":820,"sourceCode":"        ((Closeable) proxy).close();\n        return;\n      } else {\n        InvocationHandler handler = Proxy.getInvocationHandler(proxy);\n        if (handler instanceof Closeable) {\n          ((Closeable) handler).close();\n          return;\n        }\n      }\n    } catch (IOException e) {\n      LOG.error(\"Closing proxy or invocation handler caused exception\", e);\n    } catch (IllegalArgumentException e) {\n      LOG.error(\"RPC.stopProxy called on non proxy: class=\" + proxy.getClass().getName(), e);\n    }\n    \n    // If you see this error on a mock object in a unit test you're\n    // developing, make sure to use MockitoUtil.mockProtocol() to\n    // create your mock.\n    throw new HadoopIllegalArgumentException(\n        \"Cannot close proxy - is not Closeable or \"\n            + \"does not provide closeable invocation handler \"\n            + proxy.getClass());\n  }\n  /**\n   * Get the RPC time from configuration;\n   * If not set in the configuration, return the default value.\n   *\n   * @param conf Configuration\n   * @return the RPC timeout (ms)\n   */\n  public static int getRpcTimeout(Configuration conf) {\n    return conf.getInt(CommonConfigurationKeys.IPC_CLIENT_RPC_TIMEOUT_KEY,\n        CommonConfigurationKeys.IPC_CLIENT_RPC_TIMEOUT_DEFAULT);\n  }\n\n  /**\n   * Class to construct instances of RPC server with specific options.","sourceCodeStart":802,"sourceCodeEnd":838,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/RPC.java#L802-L838","documentation":"RPC.stopProxy throws HadoopIllegalArgumentException when the argument is neither Closeable nor a dynamic proxy whose InvocationHandler is Closeable — i.e., not an object the RPC layer created. The source comment names the classic cause: Mockito mocks of a protocol in unit tests, which must instead be built with MockitoUtil.mockProtocol(). It can also fire when the exception path of stopProxy (IOException/IllegalArgumentException from the close attempt) falls through to the final throw.","triggerScenarios":"Passing a Mockito mock created with Mockito.mock(MyProtocol.class) to RPC.stopProxy; passing a plain protocol implementation instance instead of the proxy object returned by RPC.getProxy/getProtocolProxy/waitForProxy; passing a non-proxy object on which Proxy.getInvocationHandler throws IllegalArgumentException and falls through to this error.","commonSituations":"Unit tests of client code closing mocked protocols (HBase/HDFS client tests); code confusing the server-side service instance with the client-side proxy; generic cleanup utilities calling RPC.stopProxy on arbitrary objects.","solutions":["In tests, create protocol mocks with MockitoUtil.mockProtocol(MyProtocol.class) — it installs a closeable invocation handler so RPC.stopProxy works.","Only pass objects obtained from RPC.getProxy, RPC.waitForProxy, or RPC.getProtocolProxy to RPC.stopProxy.","If you hold the implementation rather than a proxy, close it via its own lifecycle method, never via RPC.stopProxy.","In generic cleanup code, guard first: skip objects that are not Closeable and whose invocation handler is not Closeable."],"exampleFix":"// before\nClientProtocol nn = Mockito.mock(ClientProtocol.class);\n// ... test body ...\nRPC.stopProxy(nn); // HadoopIllegalArgumentException\n// after\nClientProtocol nn = MockitoUtil.mockProtocol(ClientProtocol.class);\n// ... test body ...\nRPC.stopProxy(nn); // closeable handler installed, no throw","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"static boolean isStoppableProxy(Object o) {\n  if (o == null || !Proxy.isProxyClass(o.getClass())) {\n    return false;\n  }\n  if (o instanceof Closeable) {\n    return true;\n  }\n  return Proxy.getInvocationHandler(o) instanceof Closeable;\n}","tryCatchPattern":null,"preventionTips":["Create protocol mocks with MockitoUtil.mockProtocol, never Mockito.mock, when tests will call RPC.stopProxy.","Keep the exact object returned by RPC.getProxy for later cleanup — do not substitute lookalikes.","In generic cleanup utilities, skip objects failing the stoppable-proxy check instead of calling stopProxy unconditionally."],"tags":["rpc","lifecycle","mockito","unit-test","cleanup"],"backgroundTag":"invalid-argument-type","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}