java-native-access/jna · error · IOException

klib.GetLastError()

klib.GetLastError()

Error message

Unable to open <file> (<GetLastError>)

What it means

W32FileMonitor.watch opens the directory with CreateFile (FILE_LIST_DIRECTORY) to monitor changes. If CreateFile returns INVALID_HANDLE_VALUE, an IOException containing the GetLastError code is thrown, meaning the directory could not be opened for change notification.

Solutions

  1. Check File.exists() and directory readability immediately before addWatch
  2. Run the application under an account with sufficient permissions for the target directory
  3. Handle the IOException and retry with a corrected/validated path
  4. Avoid watching network/removable paths that may be unavailable

Example fix

// before
monitor.addWatch(dir, listener);
// after
if (dir.exists() && dir.isDirectory()) {
    try {
        monitor.addWatch(dir, listener);
    } catch (IOException e) {
        // handle ERROR_ACCESS_DENIED etc.
    }
}
Defensive patterns

Strategy: validation

Validate before calling

if (!file.exists() || !file.isDirectory() || !file.canRead()) {
    throw new IllegalArgumentException("Cannot watch: " + file);
}

Try / catch

try {
    monitor.addWatch(dir, listener);
} catch (IOException e) {
    // GetLastError code is embedded in the message; handle access-denied explicitly
}

Prevention

When it happens

Trigger: CreateFile fails when opening the watch target: directory does not exist, access denied (ERROR_ACCESS_DENIED=5), invalid path characters, or the path maps to a file rather than a directory on an OS/handle combination that disallows it.

Common situations: Watching a directory the process lacks read permission for; race where the folder is deleted between the ancestor check and CreateFile; watching a mapped drive that is offline.

Understand the failure class

Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.

Related errors


AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12). Data as JSON: /api/errors/ba1855df396554f1. Report an issue: GitHub.

Appendix: source

Thrown at contrib/platform/src/com/sun/jna/platform/win32/W32FileMonitor.java:193

        }
        while (dir != null && !dir.exists()) {
            recursive = true;
            dir = dir.getParentFile();
        }
        if (dir == null) {
            throw new FileNotFoundException("No ancestor found for " + file);
        }
        Kernel32 klib = Kernel32.INSTANCE;
        int mask = WinNT.FILE_SHARE_READ
            | WinNT.FILE_SHARE_WRITE | WinNT.FILE_SHARE_DELETE;
        int flags = WinNT.FILE_FLAG_BACKUP_SEMANTICS
            | WinNT.FILE_FLAG_OVERLAPPED;
        HANDLE handle = klib.CreateFile(file.getAbsolutePath(),
                WinNT.FILE_LIST_DIRECTORY,
                mask, null, WinNT.OPEN_EXISTING,
                flags, null);
        if (WinBase.INVALID_HANDLE_VALUE.equals(handle)) {
            throw new IOException("Unable to open " + file + " ("
                                  + klib.GetLastError() + ")");
        }
        int notifyMask = convertMask(eventMask);
        FileInfo finfo = new FileInfo(file, handle, notifyMask, recursive);
        fileMap.put(file, finfo);
        handleMap.put(handle, finfo);
        // Existing port is returned
        port = klib.CreateIoCompletionPort(handle, port, handle.getPointer(), 0);
        if (WinBase.INVALID_HANDLE_VALUE.equals(port)) {
            throw new IOException("Unable to create/use I/O Completion port "
                    + "for " + file + " ("
                    + klib.GetLastError() + ")");
        }
        // TODO: use FileIOCompletionRoutine callback method instead of a
        // dedicated thread
        if (!klib.ReadDirectoryChangesW(handle, finfo.info, finfo.info.size(),
                                        recursive, notifyMask, finfo.infoLength,
                                        finfo.overlapped, null)) {

View on GitHub (pinned to d036ad9781)