java-native-access/jna · error · IOException
err
err
Error message
ReadDirectoryChangesW failed on <file>: '<message>' (<err>)
What it means
The background watcher thread of W32FileMonitor calls ReadDirectoryChangesW to register/change-buffer reads on the watched directory. When the native call fails (returns FALSE) while the monitor is not shutting down, an IOException with the formatted Win32 error message and code is thrown, aborting directory change monitoring for that file.
Solutions
- Catch the IOException from the monitor and re-register the watch once the directory is recreated/reconnected
- Verify the watched directory exists and is accessible before and during monitoring
- Use a local (non-network) directory when possible, as SMB shares commonly fail mid-watch
- Stop the monitor explicitly when disposing to avoid spurious errors from the race with disposal
Example fix
// before
W32FileMonitor monitor = new W32FileMonitor();
monitor.addWatch(dir, listener);
// after
W32FileMonitor monitor = new W32FileMonitor();
try {
monitor.addWatch(dir, listener);
} catch (IOException e) {
// directory vanished or was denied; retry after ensuring it exists
if (dir.mkdirs()) monitor.addWatch(dir, listener);
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!dir.exists() || !dir.isDirectory()) {
throw new IllegalStateException("Watch target missing: " + dir);
} Try / catch
try {
monitor.addWatch(dir, listener);
} catch (IOException e) {
// parse Win32 code from message, re-register or degrade to polling
} Prevention
- Don't watch network/removable drives long-term
- Stop the monitor before disposing to avoid shutdown races
- Re-create the watch after the directory is recreated or reconnected
When it happens
Trigger: The monitored directory handle becomes invalid (directory deleted/renamed, network share disconnected) while the monitor thread is running; the ReadDirectoryChangesW call inside handleChanges fails with a Win32 error such as ERROR_ACCESS_DENIED (5).
Common situations: Watching a directory on a removable or network drive that gets disconnected; the watched folder is deleted while the monitor is active; permission changes on the folder mid-watch.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- klib.GetLastError()
- No ancestor found for
- Bad volume GUID path format:
- Device context did not release properly.
- Expected GetTokenInformation to fail with…
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/6f3e29b96678e9a8.
Report an issue: GitHub.
Appendix: source
Thrown at contrib/platform/src/com/sun/jna/platform/win32/W32FileMonitor.java:118
if (event != null) {
notify(event);
}
fni = fni.next();
} while (fni != null);
// trigger the next read
if (!finfo.file.exists()) {
unwatch(finfo.file);
return;
}
if (!klib.ReadDirectoryChangesW(finfo.handle, finfo.info,
finfo.info.size(), finfo.recursive, finfo.notifyMask,
finfo.infoLength, finfo.overlapped, null)) {
if (!disposing) {
int err = klib.GetLastError();
throw new IOException("ReadDirectoryChangesW failed on "
+ finfo.file + ": '"
+ Kernel32Util.formatMessageFromLastErrorCode(err)
+ "' (" + err + ")");
}
}
}
private FileInfo waitForChange() {
IntByReference rcount = new IntByReference();
ULONG_PTRByReference rkey = new ULONG_PTRByReference();
PointerByReference roverlap = new PointerByReference();
if (! Kernel32.INSTANCE.GetQueuedCompletionStatus(port, rcount, rkey, roverlap, WinBase.INFINITE)) {
return null;
}
synchronized (this) {
return handleMap.get(new HANDLE(rkey.getValue().toPointer()));
}
}View on GitHub (pinned to d036ad9781)