{"record":{"id":"ff528df0cfde2f5b","repo":"java-native-access/jna","slug":"win32exception-from-native-getlasterror-after-openthread","errorCode":null,"errorMessage":"Win32Exception from native GetLastError after OpenThread failed","messagePattern":"Win32Exception from native GetLastError after OpenThread failed","errorType":"error_code","errorClass":"Win32Exception","httpStatus":null,"severity":"error","filePath":"contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java","lineNumber":1411,"sourceCode":"                throw new Win32Exception(Kernel32.INSTANCE.GetLastError());\n            }\n        } catch (final Win32Exception e) {\n            we = e;\n        } finally {\n            cleanUp(hProcess, we);\n        }\n    }\n\n    /**\n     * Gets the priority value of the specified thread.\n     *\n     * @param tid Identifier for the running thread.\n     * @throws Win32Exception if an error occurs.\n     */\n    public static int getThreadPriority(final int tid) {\n        final HANDLE hThread = Kernel32.INSTANCE.OpenThread(WinNT.THREAD_QUERY_INFORMATION, false, tid);\n        if (hThread == null) {\n            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());\n        }\n\n        Win32Exception we = null;\n        try {\n            final int nPriority = Kernel32.INSTANCE.GetThreadPriority(hThread);\n            if (!isValidThreadPriority(nPriority)) {\n                throw new Win32Exception(Kernel32.INSTANCE.GetLastError());\n            }\n            return nPriority;\n        } catch (final Win32Exception e) {\n            throw we = e; // re-throw to avoid return value!\n        } finally {\n            cleanUp(hThread, we);\n        }\n    }\n\n    /**\n     * Sets the priority value for the specified thread.","sourceCodeStart":1393,"sourceCodeEnd":1429,"githubUrl":"https://github.com/java-native-access/jna/blob/d036ad9781adad4b66693e8fa7098e4ac665e0a3/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java#L1393-L1429","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nint prio = Kernel32Util.getThreadPriority(tid);\n// after\ntry {\n    int prio = Kernel32Util.getThreadPriority(tid);\n} catch (Win32Exception e) {\n    LOGGER.debug(\"Cannot query thread \" + tid + \" (may have exited): \" + e.getMessage());\n}","handlingStrategy":"try-catch","validationCode":"// verify the tid is currently openable before querying\nHANDLE h = Kernel32.INSTANCE.OpenThread(WinNT.THREAD_QUERY_LIMITED_INFORMATION, false, tid);\nif (h == null) throw new IllegalStateException(\"tid \" + tid + \" not accessible (err \" + Kernel32.INSTANCE.GetLastError() + \")\");\nKernel32.INSTANCE.CloseHandle(h);","typeGuard":"boolean canQueryThread(int tid) {\n    HANDLE h = Kernel32.INSTANCE.OpenThread(WinNT.THREAD_QUERY_LIMITED_INFORMATION, false, tid);\n    if (h != null) Kernel32.INSTANCE.CloseHandle(h);\n    return h != null;\n}","tryCatchPattern":"try {\n    int prio = Kernel32Util.getThreadPriority(tid);\n} catch (Win32Exception e) {\n    int code = e.getHR().intValue() & 0xFFFF; // 5=access denied, 87=bad/stale tid\n    LOGGER.debug(\"getThreadPriority(\" + tid + \") failed, win32 code \" + code);\n    return UNAVAILABLE;\n}","preventionTips":["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."],"tags":["win32","windows","thread","permissions","jna"],"backgroundTag":"permission-denied","analyzedSha":"d036ad9781adad4b66693e8fa7098e4ac665e0a3","analyzedAt":"2026-09-12T06:50:59.239Z","contentChangedAt":"2026-09-12T06:50:59.239Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}