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
- Verify the name resolves first: URL u = cl.getResource(resourceName); adjust until it is non-null.
- Use the fully-qualified path including package directories, e.g. 'org/apache/hadoop/fs/commons-default.xml' (absolute) or call with getClass().getResource semantics.
- Check the packaged artifact (unzip -l app.jar | grep <name>) and fix pom/resource includes if the file was excluded.
- 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
- Prove the path with cl.getResource(name) before opening the stream.
- Keep resource names in constants derived from the owning class's package.
- Verify packaged jars contain the resource (unzip -l) in CI smoke checks.
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
- webapps/{} not found in CLASSPATH
- ${resource}
- Can not read resource file '{}' because class loader of the
- Can not read resource file '{}' because given class loader i
- Resource not found during scripts prepare: " + res
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/e6d7cf852e104118.
Report an issue: GitHub.