oracle/graal · error · IOException
parent directory doesn't exist for: {resourcePath}
Error message
parent directory doesn't exist for: {resourcePath} What it means
WatcherThread.addWatch registers a filesystem watch for a file path but must watch its parent directory. Path.getParent() returns null when the path has no parent (a root like '/' or a relative single name), which the code reports as IOException('parent directory doesn't exist for: ...').
Source
Thrown at espresso/src/com.oracle.truffle.espresso.hotswap/src/com/oracle/truffle/espresso/hotswap/ServiceWatcher.java:279
// Map all active file watches with the set of paths for which the watch was
// registered to enable us to cancel watches when deleted folders are recreated.
// A counter on each path reason is kept for managing when we should cancel the
// file system watch on the registered path.
private final Map<Path, Map<Path, Integer>> activeFileWatches = new HashMap<>();
private WatcherThread() throws IOException {
super("hotswap-watcher-1");
this.setDaemon(true);
this.watchService = FileSystems.getDefault().newWatchService();
}
public void addWatch(Path resourcePath, Runnable callback) throws IOException {
watchActions.put(resourcePath, new ServiceWatcher.State(calculateChecksum(resourcePath), callback));
// register watch on parent folder
Path dir = resourcePath.getParent();
if (dir == null) {
throw new IOException("parent directory doesn't exist for: " + resourcePath);
}
registerFileSystemWatch(dir, resourcePath, ALL_WATCH_KINDS);
}
private void addWatchedDeletedFolder(Path path, Path leaf) {
Set<Path> set = watchedForDeletion.get(path);
if (set == null) {
set = new HashSet<>();
watchedForDeletion.put(path, set);
}
set.add(leaf);
}
private void addWatchedCreatedFolder(Path path, Path leaf) {
Set<Path> set = watchedForCreation.get(path);
if (set == null) {
set = new HashSet<>();
watchedForCreation.put(path, set);View on GitHub (pinned to a66e9ccd1d)
Solutions
- Pass an absolute, non-root file path (a real file inside a directory) to addWatch.
- Normalize with path.toAbsolutePath().normalize() before registering.
- Guard: if path.getParent() == null, skip or report instead of registering.
Example fix
// before
watcher.addWatch(Path.of("services.cfg")); // relative, parent may be null
// after
Path p = Path.of("services.cfg").toAbsolutePath().normalize();
if (p.getParent() != null) {
watcher.addWatch(p);
} Defensive patterns
Strategy: validation
Validate before calling
Path abs = path.toAbsolutePath().normalize();
if (abs.getParent() != null) {
watcher.addWatch(abs, callback);
} Prevention
- Always pass absolute, non-root file paths to filesystem watchers.
- Normalize paths derived from URLs before use.
When it happens
Trigger: addWatch called with a root path ('/') or a bare relative filename with no directory component while the service watcher tries to register the containing folder.
Common situations: Resource URLs resolving to filesystem roots; mis-resolved URL.toURI() producing root-level paths; relative paths used from an unexpected working directory.
Related errors
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/9373c15f904a3aef.
Report an issue: GitHub.