java-native-access/jna · error · Win32Exception

Win32Exception (error code from GetLastError after…

Error message

Win32Exception (error code from GetLastError after GetPrinter)

What it means

WinspoolUtil.getPrinterInfo2() opens a printer and calls the Win32 GetPrinter API with level 2. If GetPrinter returns FALSE, the native error code from GetLastError is wrapped in a Win32Exception and thrown. This means the printer handle/level/buffer combination was rejected by the spooler.

Solutions

  1. Check the Win32Exception's errorCode (e.g. 5 = access denied, 87 = invalid parameter, 1801 = invalid printer name) and fix the underlying cause.
  2. Verify the printer name passed to OpenPrinter is valid and the printer exists (use getPrinterNames/EnumPrinters first).
  3. Run the process under an account with permissions on the target printer; for network printers ensure the spooler is reachable.
  4. Re-check that the printer still exists between the size-query and data call; retry getPrinterInfo2 if the error is transient.

Example fix

// before
PRINTER_INFO_2 info = WinspoolUtil.getPrinterInfo2(printerName);
// after
if (!WinspoolUtil.getPrinterNames().contains(printerName)) {
    throw new IllegalArgumentException("Printer not found: " + printerName);
}
try {
    PRINTER_INFO_2 info = WinspoolUtil.getPrinterInfo2(printerName);
} catch (Win32Exception e) {
    if (e.getErrorCode() == W32Errors.ERROR_ACCESS_DENIED) {
        throw new IllegalStateException("No permission for printer " + printerName, e);
    }
    throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

boolean printerExists(String name) {
    return WinspoolUtil.getPrinterNames().stream().anyMatch(n -> n.equalsIgnoreCase(name));
}

Try / catch

try {
    PRINTER_INFO_2 info = WinspoolUtil.getPrinterInfo2(name);
} catch (Win32Exception e) {
    switch (e.getErrorCode()) {
        case 5: throw new SecurityException("Access denied for printer " + name, e);
        case 1801: throw new IllegalArgumentException("Invalid printer name", e);
        default: throw e;
    }
}

Prevention

When it happens

Trigger: Calling getPrinterInfo2 with an invalid or closed printer handle, insufficient rights on the printer, or the spooler rejecting the level-2 GetPrinter call after the initial buffer-size call succeeded (e.g. printer deleted or access revoked between the two calls).

Common situations: Querying a network printer that has gone offline, running without printer-access privileges (e.g. service account lacking printer permissions), or a race where the printer is removed while the handle is open.

Related errors


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

Appendix: source

Thrown at contrib/platform/src/com/sun/jna/platform/win32/WinspoolUtil.java:119

        IntByReference pcReturned = new IntByReference();
        HANDLEByReference pHandle = new HANDLEByReference();

        if (!Winspool.INSTANCE.OpenPrinter(printerName, pHandle, null)) {
            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
        }

        Win32Exception we = null;
        PRINTER_INFO_2 pinfo2 = null;

        try {
            Winspool.INSTANCE.GetPrinter(pHandle.getValue(), 2, null, 0, pcbNeeded);
            if (pcbNeeded.getValue() <= 0) {
                return new PRINTER_INFO_2();
            }

            pinfo2 = new PRINTER_INFO_2(pcbNeeded.getValue());
            if (!Winspool.INSTANCE.GetPrinter(pHandle.getValue(), 2, pinfo2.getPointer(), pcbNeeded.getValue(), pcReturned)) {
                throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
            }

            pinfo2.read();
        } catch (Win32Exception e) {
            we = e;
        } finally {
            if (!Winspool.INSTANCE.ClosePrinter(pHandle.getValue())) {
                Win32Exception ex = new Win32Exception(Kernel32.INSTANCE.GetLastError());
                if (we != null) {
                    ex.addSuppressedReflected(we);
                }
            }
        }

        if (we != null) {
            throw we;
        }

View on GitHub (pinned to d036ad9781)