oracle/graal · error · IOException
Resource {resource} not found from class loader: {loaderClas
Error message
Resource {resource} not found from class loader: {loaderClassName} What it means
ServiceWatcher (hotswap agent support) resolves a resource name through a class loader to get a URL it can watch for changes. If the loader cannot find the resource, the URL is null and it throws IOException naming the resource and loader class; watching META-INF/services files is meaningless when the file does not exist.
Source
Thrown at espresso/src/com.oracle.truffle.espresso.hotswap/src/com/oracle/truffle/espresso/hotswap/ServiceWatcher.java:114
StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.OVERFLOW};
private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
private final Map<String, Set<String>> services = new HashMap<>(4);
private WatcherThread serviceWatcherThread;
private URLWatcher urlWatcher;
public boolean addResourceWatcher(ClassLoader loader, String resource, HotSwapAction callback) throws IOException {
ensureInitialized();
URL url;
if (loader == null) {
url = ClassLoader.getSystemResource(resource);
} else {
url = loader.getResource(resource);
}
if (url == null) {
throw new IOException("Resource " + resource + " not found from class loader: " + loader.getClass().getName());
}
if ("file".equals(url.getProtocol())) {
// parent directory to register watch on
try {
Path path = Paths.get(url.toURI());
serviceWatcherThread.addWatch(path, () -> callback.fire());
return true;
} catch (URISyntaxException e) {
return false;
}
}
return false;
}
public synchronized void addServiceWatcher(Class<?> service, ClassLoader loader, HotSwapAction callback) throws IOException {
ensureInitialized();
// cache initial service implementationsView on GitHub (pinned to a66e9ccd1d)
Solutions
- Verify the resource exists for that exact loader: loader.getResource(name) != null before registering the watcher.
- Fix the resource path spelling and ensure it is on the classpath/module path of the loader passed in.
- When shading, keep META-INF/services entries (e.g. ServicesResourceTransformer in Maven Shade).
Example fix
// before
watcher.addResourceWatcher(loader, "META-INF/services/com.acme.Api", cb); // may throw
// after
String res = "META-INF/services/com.acme.Api";
if (loader.getResource(res) != null) {
watcher.addResourceWatcher(loader, res, cb);
} else {
// log / skip watching
} Defensive patterns
Strategy: validation
Validate before calling
URL u = (loader == null) ? ClassLoader.getSystemResource(res) : loader.getResource(res);
if (u == null) { /* skip or report; do not call addResourceWatcher */ } Try / catch
try {
watcher.addResourceWatcher(loader, res, cb);
} catch (IOException e) {
if (e.getMessage().contains("not found from class loader")) { /* resource absent; skip watching */ }
} Prevention
- Check getResource() before registering watchers.
- Keep META-INF/services files through shading builds.
When it happens
Trigger: addResourceWatcher(loader, resource, callback) with a resource path that is misspelled, lives in a different module/classloader, or is packaged in a jar the loader cannot see (or is null loader -> system resource missing).
Common situations: HotSwap tooling watching 'META-INF/services/...' files that were stripped during shading; resources renamed between library versions; modularized apps where the service file sits in a non-visible layer.
Related errors
- non-public interface is not defined by the given loader
- InvalidClassFormat
- UnsupportedVersion
- NamesDontMatch
- FailsVerification
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/f2c0025a5640fa1d.
Report an issue: GitHub.