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

  1. Pair every setCurrentThreadBackgroundMode(true) with a matching (false) in a finally block, on the same thread.
  2. Run elevated when enabling background mode since it requires additional privilege.
  3. Check Win32Exception.getErrorCode(): ERROR_PROCESS_MODE_ALREADY_BACKGROUND / NOT_BACKGROUND indicate unbalanced begin/end calls.
  4. 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

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


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