java-native-access/jna · error · Win32Exception
Win32Exception from native GetLastError after SetThreadPrior
Error message
Win32Exception from native GetLastError after SetThreadPriority (background mode) failed
What it means
setCurrentThreadBackgroundMode(boolean) maps 'enable' to THREAD_MODE_BACKGROUND_BEGIN or THREAD_MODE_BACKGROUND_END and calls SetThreadPriority on the current thread. If the native call fails, the library throws a Win32Exception from GetLastError(). Background-begin requires an elevated context and background-end fails if background mode was never started.
Source
Thrown at contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java:1343
if (!isValidThreadPriority(nPriority)) {
throw new IllegalArgumentException("The given priority value is invalid!");
}
if (!Kernel32.INSTANCE.SetThreadPriority(Kernel32.INSTANCE.GetCurrentThread(), nPriority)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
}
/**
* Enables or disables "background" processing mode for the current thread
*
* @param enable If true, enables "background" processing mode, otherwise disables it.
* @throws Win32Exception if an error occurs.
*/
public static void setCurrentThreadBackgroundMode(final boolean enable) {
// Note: THREAD_MODE_BACKGROUND_{BEGIN,END} only works with the "current" thread handle!
final int nPriority = enable ? Kernel32.THREAD_MODE_BACKGROUND_BEGIN : Kernel32.THREAD_MODE_BACKGROUND_END;
if (!Kernel32.INSTANCE.SetThreadPriority(Kernel32.INSTANCE.GetCurrentThread(), nPriority)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
}
/**
* Gets the priority class of the specified process.
*
* @param pid Identifier for the running process.
* @throws Win32Exception if an error occurs.
*/
public static DWORD getProcessPriority(final int pid) {
final HANDLE hProcess = Kernel32.INSTANCE.OpenProcess(WinNT.PROCESS_QUERY_INFORMATION , false, pid);
if (hProcess == null) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
Win32Exception we = null;
try {
final DWORD dwPriorityClass = Kernel32.INSTANCE.GetPriorityClass(hProcess);View on GitHub (pinned to d036ad9781)
Solutions
- Pair every setCurrentThreadBackgroundMode(true) with a matching (false) in a finally block, on the same thread.
- Run elevated when enabling background mode since it requires additional privilege.
- Check Win32Exception.getErrorCode(): ERROR_PROCESS_MODE_ALREADY_BACKGROUND / NOT_BACKGROUND indicate unbalanced begin/end calls.
- Fall back to SetThreadPriority(THREAD_PRIORITY_LOWEST) or SetThreadInformation thread I/O priority if background mode is unavailable.
Example fix
// before
Kernel32Util.setCurrentThreadBackgroundMode(true);
doIoHeavyWork();
Kernel32Util.setCurrentThreadBackgroundMode(false);
// after
boolean bg = false;
try {
Kernel32Util.setCurrentThreadBackgroundMode(true);
bg = true;
doIoHeavyWork();
} finally {
if (bg) Kernel32Util.setCurrentThreadBackgroundMode(false);
} Defensive patterns
Strategy: try-catch
Validate before calling
// track per-thread state to keep begin/end balanced:
if (enable && BACKGROUND_ACTIVE.get()) { throw new IllegalStateException("background mode already active"); }
if (!enable && !BACKGROUND_ACTIVE.get()) { return; } Try / catch
try {
Kernel32Util.setCurrentThreadBackgroundMode(true);
BACKGROUND_ACTIVE.set(true);
} catch (Win32Exception e) {
log.warn("Thread background mode failed: {}", e.getErrorCode());
} finally {
if (BACKGROUND_ACTIVE.get()) {
Kernel32Util.setCurrentThreadBackgroundMode(false);
BACKGROUND_ACTIVE.set(false);
}
} Prevention
- Background mode is per-thread: begin and end must run on the same thread — use ThreadLocal state.
- Put the 'end' call in a finally block to keep pairs balanced across exceptions.
- Require elevation for THREAD_MODE_BACKGROUND_BEGIN.
- Fall back to THREAD_PRIORITY_LOWEST when background mode is unavailable.
When it happens
Trigger: Calling Kernel32Util.setCurrentThreadBackgroundMode(true) from a non-elevated thread (needs privilege), or setCurrentThreadBackgroundMode(false) when background mode was never enabled — SetPriorityClass-style native failure propagates as Win32Exception.
Common situations: Unbalanced begin/end pairs across worker threads (background mode is per-thread); non-admin processes attempting to lower their I/O priority; Windows editions or job objects that reject background mode.
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
- Win32Exception from native GetLastError after SetPriorityCla
- Win32Exception from native GetLastError when GetThreadPriori
- Win32Exception from native GetLastError after SetThreadPrior
- LookupAccountNameW was expected to fail with ERROR_INSUFFICI
- Expected GetTokenInformation to fail with ERROR_INSUFFICIENT
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/2fa3ac702155c4c2.
Report an issue: GitHub.