apache/hadoop · error · IOException

Can not read resource file '{}'

Error message

Can not read resource file '{}'

What it means

After resolving a non-null classloader, ThreadUtil.getResourceAsStream asks it for the named resource; ClassLoader.getResourceAsStream returns null (rather than throwing) when nothing matches at that name on the classpath, and this method converts that null into an IOException. So this error means 'the loader is fine, but no resource exists at that path for it'.

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/ThreadUtil.java:121

   * classpath using given classloader.
   * <p>
   *
   * @param cl ClassLoader to be used to retrieve resource.
   * @param resourceName resource to retrieve.
   *
   * @throws IOException thrown if resource cannot be loaded
   * @return inputstream with the resource.
   */
  public static InputStream getResourceAsStream(ClassLoader cl,
        String resourceName)
        throws IOException {
    if (cl == null) {
      throw new IOException("Can not read resource file '" + resourceName +
          "' because given class loader is null");
    }
    InputStream is = cl.getResourceAsStream(resourceName);
    if (is == null) {
      throw new IOException("Can not read resource file '" +
          resourceName + "'");
    }
    return is;
  }


}

View on GitHub (pinned to 2add963021)

Solutions

  1. Verify the name resolves first: URL u = cl.getResource(resourceName); adjust until it is non-null.
  2. Use the fully-qualified path including package directories, e.g. 'org/apache/hadoop/fs/commons-default.xml' (absolute) or call with getClass().getResource semantics.
  3. Check the packaged artifact (unzip -l app.jar | grep <name>) and fix pom/resource includes if the file was excluded.
  4. Pass the classloader whose classpath actually contains the resource instead of relying on the TCCL.

Example fix

// before
InputStream is = ThreadUtil.getResourceAsStream(cl, "core-default.xml");
// throws: Can not read resource file 'core-default.xml' (lives under org/apache/hadoop/)

// after
InputStream is = ThreadUtil.getResourceAsStream(cl,
    "org/apache/hadoop/core-default.xml");
Defensive patterns

Strategy: validation

Validate before calling

if (cl.getResource(resourceName) == null) {
  throw new FileNotFoundException(
      "Resource '" + resourceName + "' not found on " + cl
      + "; expected on the classpath, check packaging");
}
InputStream is = ThreadUtil.getResourceAsStream(cl, resourceName);

Try / catch

try {
  is = ThreadUtil.getResourceAsStream(cl, resourceName);
} catch (IOException e) {
  // name-resolution miss: try package-qualified variants
  for (String alt : altResourcePaths(resourceName)) {
    is = cl.getResourceAsStream(alt);
    if (is != null) break;
  }
  if (is == null) throw e;
}

Prevention

When it happens

Trigger: Wrong resource name: 'core-default.xml' when the file lives under 'org/apache/hadoop/' — absolute names need the full package path with or without a leading '/'; resources excluded from the packaged jar; shaded/relocated jars that moved resources; using the TCCL when the resource is only visible to the application classloader.

Common situations: src/main/resources file filtered out of the build; running a skinny jar where the resource is in a dependency jar that is missing; typo or case mismatch in the path; Maven shade plugin dropping transformer-handled resources; tests with a classpath that lacks the resource module.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/e6d7cf852e104118. Report an issue: GitHub.