{"record":{"id":"1d32183ed8276525","repo":"apache/hadoop","slug":"unbound-method","errorCode":null,"errorMessage":"Unbound ${method}","messagePattern":"Unbound (.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/wrappedio/impl/DynamicWrappedIO.java","lineNumber":239,"sourceCode":"  /**\n   * For testing: verify that all methods were found.\n   * @throws UnsupportedOperationException if the method was not found.\n   */\n  void requireAllMethodsAvailable()  throws UnsupportedOperationException {\n\n    final DynMethods.UnboundMethod[] methods = {\n        bulkDeleteDeleteMethod,\n        bulkDeletePageSizeMethod,\n        fileSystemOpenFileMethod,\n        pathCapabilitiesHasPathCapabilityMethod,\n        streamCapabilitiesHasCapabilityMethod,\n        byteBufferPositionedReadableReadFullyAvailableMethod,\n        byteBufferPositionedReadableReadFullyMethod,\n    };\n    for (DynMethods.UnboundMethod method : methods) {\n      LOG.info(\"Checking method {}\", method);\n      if (!available(method)) {\n        throw new UnsupportedOperationException(\"Unbound \" + method);\n      }\n    }\n  }\n\n\n  /**\n   * Are the bulk delete methods available?\n   * @return true if the methods were found.\n   */\n  public boolean bulkDelete_available() {\n    return available(bulkDeleteDeleteMethod);\n  }\n\n  /**\n   * Get the maximum number of objects/files to delete in a single request.\n   * @param fileSystem filesystem\n   * @param path path to delete under.\n   * @return a number greater than or equal to zero.","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/wrappedio/impl/DynamicWrappedIO.java#L221-L257","documentation":"DynamicWrappedIO binds seven static methods of org.apache.hadoop.io.wrappedio.WrappedIO reflectively via DynMethods (bulkDelete_delete, bulkDelete_pageSize, fileSystem_openFile, pathCapabilities_hasPathCapability, streamCapabilities_hasCapability, byteBufferPositionedReadable_readFullyAvailable, byteBufferPositionedReadable_readFully). requireAllMethodsAvailable() throws UnsupportedOperationException(\"Unbound \" + method) when any binding is null — meaning the WrappedIO class was found but does not contain that exact static method with the expected signature (or was not found at all, leaving every method unbound).","triggerScenarios":"Instantiating DynamicWrappedIO against a hadoop-common jar older or newer than the WrappedIO API this class expects (method renamed, added, or signature changed); the WrappedIO class absent from the classpath (loadClass returns null so all loadStaticMethod calls yield unbound methods); duplicate/shaded copies of hadoop-common where an older WrappedIO wins classloading; invoking requireAllMethodsAvailable() in tests after a version bump.","commonSituations":"Version drift between hadoop-common artifacts on one classpath; third-party stores copying DynamicWrappedIO into their codebase (the 'copy-and-paste adoption' the loaded flag mentions); dependency shading pinning an older hadoop-common; upgrading Hadoop in a project that vendors this adapter.","solutions":["Align hadoop-common versions across the classpath: inspect with mvn dependency:tree or dump java.classpath and remove/upgrade the stray older hadoop-common jar.","At startup check DynamicWrappedIO.loaded() and the per-API probes (bulkDelete_available(), etc.) instead of assuming all methods are bound.","If you vendored a copy of DynamicWrappedIO, update the method-name constants and signatures to match the WrappedIO version actually on your classpath.","Look for shaded/duplicate org.apache.hadoop classes (jar tf | grep 'wrappedio/WrappedIO') and keep exactly one version."],"exampleFix":"// before\nnew DynamicWrappedIO().requireAllMethodsAvailable(); // UnsupportedOperationException: Unbound ... after hadoop-common downgrade\n\n// after\nDynamicWrappedIO dio = new DynamicWrappedIO();\nif (!dio.loaded() || !dio.bulkDelete_available()) {\n  LOG.warn(\"WrappedIO incomplete on classpath; falling back to non-vectored path\");\n} else {\n  // safe to use the dynamic bindings\n}","handlingStrategy":"validation","validationCode":"DynamicWrappedIO dio = new DynamicWrappedIO();\nif (!dio.loaded()) {\n  throw new IllegalStateException(\"WrappedIO class missing from classpath\");\n}\nif (!dio.bulkDelete_available()) {\n  LOG.warn(\"bulkDelete unbound: hadoop-common version mismatch\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  dyn.requireAllMethodsAvailable();\n} catch (UnsupportedOperationException e) {\n  // name the unbound method; audit classpath for duplicate/old hadoop-common jars\n  LOG.error(\"WrappedIO binding incomplete: {}\", e.getMessage());\n}","preventionTips":["Enforce a single hadoop-common version via dependencyManagement and check with dependency:tree in CI.","Probe loaded() and per-API *_available() before first use, not requireAllMethodsAvailable() blindly.","If vendoring DynamicWrappedIO, keep its method constants in lockstep with the WrappedIO version you target.","Add a smoke test that constructs DynamicWrappedIO() in the assembled (shaded) jar, not just in the reactor."],"tags":["hadoop","reflection","dynmethods","classpath","version-mismatch","wrappedio","dependency-conflict"],"backgroundTag":"classpath-version-mismatch","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}