java-native-access/jna · error · Win32Exception

Win32Exception from native GetLastError after SetPriorityCla

Error message

Win32Exception from native GetLastError after SetPriorityClass (background mode) failed

What it means

setCurrentProcessBackgroundMode(boolean) maps 'enable' to PROCESS_MODE_BACKGROUND_BEGIN or PROCESS_MODE_BACKGROUND_END and calls SetPriorityClass on the current process. If the native call returns FALSE, the library throws a Win32Exception from GetLastError(). Background-begin mode requires elevated privileges and a process that is not a background process already; background-end fails when background mode was never started.

Source

Thrown at contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java:1300

        if (!isValidPriorityClass(dwPriorityClass)) {
            throw new IllegalArgumentException("The given priority value is invalid!");
        }
        if (!Kernel32.INSTANCE.SetPriorityClass(Kernel32.INSTANCE.GetCurrentProcess(), dwPriorityClass)) {
            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
        }
    }

    /**
     * Enables or disables "background" processing mode for the current process
     *
     * @param enable If true, enables "background" processing mode, otherwise disables it.
     * @throws Win32Exception if an error occurs.
     */
    public static void setCurrentProcessBackgroundMode(final boolean enable) {
        // Note: PROCESS_MODE_BACKGROUN_{BEGIN,END} only works with the "current" process handle!
        final DWORD dwPriorityClass = enable ? Kernel32.PROCESS_MODE_BACKGROUND_BEGIN : Kernel32.PROCESS_MODE_BACKGROUND_END;
        if (!Kernel32.INSTANCE.SetPriorityClass(Kernel32.INSTANCE.GetCurrentProcess(), dwPriorityClass)) {
            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
        }
    }

    /**
     * Gets the priority value of the current thread.
     *
     * @return The priority value of the current thread.
     * @throws Win32Exception if an error occurs.
     */
    public static int getCurrentThreadPriority() {
        final int nPriority = Kernel32.INSTANCE.GetThreadPriority(Kernel32.INSTANCE.GetCurrentThread());
        if (!isValidThreadPriority(nPriority)) {
            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
        }
        return nPriority;
    }

    /**

View on GitHub (pinned to d036ad9781)

Solutions

  1. Ensure every setCurrentProcessBackgroundMode(true) is paired with exactly one (false) call in a finally block.
  2. Run elevated if enabling background mode, since BACKGROUND_BEGIN requires additional privilege.
  3. Check Win32Exception.getErrorCode(): ERROR_PROCESS_MODE_ALREADY_BACKGROUND (402) means begin was called twice; ERROR_PROCESS_MODE_NOT_BACKGROUND (403) means end without begin.
  4. Wrap in try-catch and fall back to normal priority classes if the mode switch fails.

Example fix

// before
Kernel32Util.setCurrentProcessBackgroundMode(true);
// after
boolean bg = false;
try {
    Kernel32Util.setCurrentProcessBackgroundMode(true);
    bg = true;
    // ... disk-heavy work ...
} finally {
    if (bg) Kernel32Util.setCurrentProcessBackgroundMode(false);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// background begin requires elevation:
// if (!isAdmin()) throw new IllegalStateException("background mode requires elevation");
// track state to avoid unbalanced calls:
if (enable && backgroundModeActive) { throw new IllegalStateException("background mode already active"); }
if (!enable && !backgroundModeActive) { return; } // nothing to end

Try / catch

try {
    Kernel32Util.setCurrentProcessBackgroundMode(true);
} catch (Win32Exception e) {
    // 402 = already background, 403 = not background (for 'end')
    log.warn("Background mode switch failed: {}", e.getErrorCode());
}

Prevention

When it happens

Trigger: Calling Kernel32Util.setCurrentProcessPriority-style background mode via Kernel32Util.setCurrentProcessBackgroundMode(true) without elevation, or calling setCurrentProcessBackgroundMode(false) when background mode was never enabled — both make SetPriorityClass fail with a native error.

Common situations: Non-admin processes attempting PROCESS_MODE_BACKGROUND_BEGIN (needs SeIncreaseBasePriorityPrivilege); unbalanced begin/end calls across code paths; Windows versions/job objects that reject the mode constants.

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/4da809adbff430ba. Report an issue: GitHub.