java-native-access/jna · error · Win32Exception
Win32Exception from native GetLastError after OpenThread fai
Error message
Win32Exception from native GetLastError after OpenThread failed
What it means
Kernel32Util.getThreadPriority(tid) calls OpenThread with THREAD_QUERY_INFORMATION; a NULL return is converted into a Win32Exception carrying native GetLastError(). Typical causes are a nonexistent thread id, the thread already exited, or insufficient access rights to the owning process's threads.
Source
Thrown at contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java:1411
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
} catch (final Win32Exception e) {
we = e;
} finally {
cleanUp(hProcess, we);
}
}
/**
* Gets the priority value of the specified thread.
*
* @param tid Identifier for the running thread.
* @throws Win32Exception if an error occurs.
*/
public static int getThreadPriority(final int tid) {
final HANDLE hThread = Kernel32.INSTANCE.OpenThread(WinNT.THREAD_QUERY_INFORMATION, false, tid);
if (hThread == null) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
Win32Exception we = null;
try {
final int nPriority = Kernel32.INSTANCE.GetThreadPriority(hThread);
if (!isValidThreadPriority(nPriority)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
return nPriority;
} catch (final Win32Exception e) {
throw we = e; // re-throw to avoid return value!
} finally {
cleanUp(hThread, we);
}
}
/**
* Sets the priority value for the specified thread.View on GitHub (pinned to d036ad9781)
Solutions
- Verify the tid is current (thread still running) before querying; drop ids collected earlier without refresh.
- Catch Win32Exception and check the code: 87 (ERROR_INVALID_PARAMETER) usually a bad/nonexistent tid, 5 (ERROR_ACCESS_DENIED) a permissions issue.
- Run elevated or use THREAD_QUERY_LIMITED_INFORMATION via Kernel32.INSTANCE.OpenThread directly when full query rights are denied.
- Ensure you are passing a thread id (from Win32 thread enumeration), not a process id.
- Re-enumerate threads each sampling cycle instead of caching tids across long intervals.
Example fix
// before
int prio = Kernel32Util.getThreadPriority(tid);
// after
try {
int prio = Kernel32Util.getThreadPriority(tid);
} catch (Win32Exception e) {
LOGGER.debug("Cannot query thread " + tid + " (may have exited): " + e.getMessage());
} Defensive patterns
Strategy: try-catch
Validate before calling
// verify the tid is currently openable before querying
HANDLE h = Kernel32.INSTANCE.OpenThread(WinNT.THREAD_QUERY_LIMITED_INFORMATION, false, tid);
if (h == null) throw new IllegalStateException("tid " + tid + " not accessible (err " + Kernel32.INSTANCE.GetLastError() + ")");
Kernel32.INSTANCE.CloseHandle(h); Type guard
boolean canQueryThread(int tid) {
HANDLE h = Kernel32.INSTANCE.OpenThread(WinNT.THREAD_QUERY_LIMITED_INFORMATION, false, tid);
if (h != null) Kernel32.INSTANCE.CloseHandle(h);
return h != null;
} Try / catch
try {
int prio = Kernel32Util.getThreadPriority(tid);
} catch (Win32Exception e) {
int code = e.getHR().intValue() & 0xFFFF; // 5=access denied, 87=bad/stale tid
LOGGER.debug("getThreadPriority(" + tid + ") failed, win32 code " + code);
return UNAVAILABLE;
} Prevention
- Refresh thread id lists every sampling pass; never cache tids across long intervals.
- Make sure you pass a thread id, not a process id.
- Run elevated when sampling foreign processes' threads.
- Treat per-thread failures as non-fatal in monitoring loops.
When it happens
Trigger: Calling Kernel32Util.getThreadPriority(tid) when OpenThread fails: stale tid after thread termination, tid from another process without access rights, or tid typos/incorrect id source.
Common situations: Sampling thread priorities of foreign processes from a non-elevated JVM; iterating cached thread ids while threads exit; confusing pids with tids and passing a process id instead.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- LookupAccountNameW was expected to fail with ERROR_INSUFFICI
- Expected GetTokenInformation to fail with ERROR_INSUFFICIENT
- Failed to find privilege "{privilege}" - {GetLastError}
- Win32Exception from native GetLastError after OpenProcess fa
- Win32Exception from native GetLastError after ExpandEnvironm
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/ff528df0cfde2f5b.
Report an issue: GitHub.