{"record":{"id":"ead7a7e69d22746f","repo":"apache/hadoop","slug":"can-not-read-resource-file-because-class-load","errorCode":null,"errorMessage":"Can not read resource file '{}' because class loader of the current thread is null","messagePattern":"Can not read resource file '(.+?)' because class loader of the current thread is null","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/ThreadUtil.java","lineNumber":95,"sourceCode":"    }\n  }\n\n  /**\n   * Convenience method that returns a resource as inputstream from the\n   * classpath.\n   * <p>\n   * Uses the Thread's context classloader to load resource.\n   *\n   * @param resourceName resource to retrieve.\n   *\n   * @throws IOException thrown if resource cannot be loaded\n   * @return inputstream with the resource.\n   */\n  public static InputStream getResourceAsStream(String resourceName)\n      throws IOException {\n    ClassLoader cl = Thread.currentThread().getContextClassLoader();\n    if (cl == null) {\n      throw new IOException(\"Can not read resource file '\" + resourceName +\n          \"' because class loader of the current thread is null\");\n    }\n    return getResourceAsStream(cl, resourceName);\n  }\n\n  /**\n   * Convenience method that returns a resource as inputstream from the\n   * classpath using given classloader.\n   * <p>\n   *\n   * @param cl ClassLoader to be used to retrieve resource.\n   * @param resourceName resource to retrieve.\n   *\n   * @throws IOException thrown if resource cannot be loaded\n   * @return inputstream with the resource.\n   */\n  public static InputStream getResourceAsStream(ClassLoader cl,\n        String resourceName)","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/ThreadUtil.java#L77-L113","documentation":"ThreadUtil.getResourceAsStream(String) loads a classpath resource through Thread.currentThread().getContextClassLoader(). If the current thread's context classloader is null — which happens when a thread was created without inheriting a TCCL or when something explicitly called setContextClassLoader(null) — the method throws this IOException before even attempting the lookup. The null check exists because delegating to the two-arg overload with a null loader would NPE inside the ClassLoader machinery.","triggerScenarios":"Threads created by raw constructors or thread pools in containers/applications where setContextClassLoader was never called; frameworks that clear the TCCL for classloading isolation; calling this helper from a shutdown hook or JNI-attached thread where TCCL is unset.","commonSituations":"Library code executed inside custom executor services; embedded Hadoop clients in application servers or OSGi environments that manipulate the TCCL; tests spawning worker threads that then try to read Hadoop configuration XML resources.","solutions":["Use the two-arg overload with an explicit loader: ThreadUtil.getResourceAsStream(MyClass.class.getClassLoader(), resourceName).","Set the TCCL before running the code: thread.setContextClassLoader(appClassLoader) or restore it inside the task.","Catch IOException and retry with an explicit classloader as a defensive path.","In thread factories, propagate the creating thread's TCCL to new threads."],"exampleFix":"// before\nInputStream is = ThreadUtil.getResourceAsStream(\"core-default.xml\");\n// throws: class loader of the current thread is null\n\n// after\nInputStream is = ThreadUtil.getResourceAsStream(\n    MyApp.class.getClassLoader(), \"core-default.xml\");","handlingStrategy":"validation","validationCode":"ClassLoader tccl = Thread.currentThread().getContextClassLoader();\nif (tccl == null) {\n  tccl = MyApp.class.getClassLoader(); // explicit fallback loader\n}\nInputStream is = ThreadUtil.getResourceAsStream(tccl, resourceName);","typeGuard":null,"tryCatchPattern":"try {\n  is = ThreadUtil.getResourceAsStream(resourceName);\n} catch (IOException e) {\n  // fall back to an explicit loader (null TCCL or missing resource)\n  is = MyApp.class.getClassLoader().getResourceAsStream(resourceName);\n  if (is == null) throw e;\n}","preventionTips":["In custom ThreadFactory implementations, copy the creator's TCCL onto new threads.","Prefer the two-arg overload with a class-derived loader in library code.","Never rely on TCCL being set inside shutdown hooks or JNI-attached threads."],"tags":["classloader","classpath","threading","resources","hadoop-common"],"backgroundTag":"null-classloader","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}