{"record":{"id":"f2c0025a5640fa1d","repo":"oracle/graal","slug":"resource-resource-not-found-from-class-loader","errorCode":null,"errorMessage":"Resource {resource} not found from class loader: {loaderClassName}","messagePattern":"Resource (.+?) not found from class loader: (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"espresso/src/com.oracle.truffle.espresso.hotswap/src/com/oracle/truffle/espresso/hotswap/ServiceWatcher.java","lineNumber":114,"sourceCode":"                    StandardWatchEventKinds.ENTRY_DELETE,\n                    StandardWatchEventKinds.OVERFLOW};\n\n    private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];\n\n    private final Map<String, Set<String>> services = new HashMap<>(4);\n    private WatcherThread serviceWatcherThread;\n    private URLWatcher urlWatcher;\n\n    public boolean addResourceWatcher(ClassLoader loader, String resource, HotSwapAction callback) throws IOException {\n        ensureInitialized();\n        URL url;\n        if (loader == null) {\n            url = ClassLoader.getSystemResource(resource);\n        } else {\n            url = loader.getResource(resource);\n        }\n        if (url == null) {\n            throw new IOException(\"Resource \" + resource + \" not found from class loader: \" + loader.getClass().getName());\n        }\n\n        if (\"file\".equals(url.getProtocol())) {\n            // parent directory to register watch on\n            try {\n                Path path = Paths.get(url.toURI());\n                serviceWatcherThread.addWatch(path, () -> callback.fire());\n                return true;\n            } catch (URISyntaxException e) {\n                return false;\n            }\n        }\n        return false;\n    }\n\n    public synchronized void addServiceWatcher(Class<?> service, ClassLoader loader, HotSwapAction callback) throws IOException {\n        ensureInitialized();\n        // cache initial service implementations","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/espresso/src/com.oracle.truffle.espresso.hotswap/src/com/oracle/truffle/espresso/hotswap/ServiceWatcher.java#L96-L132","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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)."],"exampleFix":"// before\nwatcher.addResourceWatcher(loader, \"META-INF/services/com.acme.Api\", cb); // may throw\n\n// after\nString res = \"META-INF/services/com.acme.Api\";\nif (loader.getResource(res) != null) {\n    watcher.addResourceWatcher(loader, res, cb);\n} else {\n    // log / skip watching\n}","handlingStrategy":"validation","validationCode":"URL u = (loader == null) ? ClassLoader.getSystemResource(res) : loader.getResource(res);\nif (u == null) { /* skip or report; do not call addResourceWatcher */ }","typeGuard":null,"tryCatchPattern":"try {\n    watcher.addResourceWatcher(loader, res, cb);\n} catch (IOException e) {\n    if (e.getMessage().contains(\"not found from class loader\")) { /* resource absent; skip watching */ }\n}","preventionTips":["Check getResource() before registering watchers.","Keep META-INF/services files through shading builds."],"tags":["espresso","hotswap","resources","classloader"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}