java-native-access/jna · error · RuntimeException
Failed to get printer change notification
Error message
Failed to get printer change notification - <errorCode>
What it means
Inside the monitor loop, FindNextPrinterChangeNotification is called to fetch the next printer-change event. If it returns FALSE, GetLastError is captured and a RuntimeException 'Failed to get printer change notification - <errorCode>' is thrown, aborting the monitoring loop mid-run.
Solutions
- Check errorCode: ERROR_INVALID_HANDLE (6) means the change handle is stale — re-open the printer and re-register with FindFirstPrinterChangeNotification.
- Catch the RuntimeException outside the while loop and rebuild the whole monitor (re-open handles) instead of terminating.
- Verify the PRINTER_NOTIFY_OPTIONS and info buffer pointer remain valid across iterations (don't free/reuse the buffer incorrectly).
- Ensure the account retains printer access for the duration of monitoring.
Example fix
// before
while (true) { ... FindNextPrinterChangeNotification(...); }
// after
while (running) {
try {
monitorOnce();
} catch (RuntimeException e) {
LOG.warn("Change notification failed, re-registering", e);
closeHandles();
reOpenAndRegister();
}
} Defensive patterns
Strategy: retry
Try / catch
boolean ok = Winspool.INSTANCE.FindNextPrinterChangeNotification(handle, change, options, infoPointer);
if (!ok) {
int err = Kernel32.INSTANCE.GetLastError();
if (err == W32Errors.ERROR_INVALID_HANDLE) { reRegisterMonitor(); }
} Prevention
- Wrap the monitor loop with handle-rebuild logic rather than letting one failure kill the monitor.
- Detect spooler restarts (ERROR_INVALID_HANDLE) and re-register.
- Keep the notification buffer/options allocations stable across iterations.
- Bound retries to avoid hot-looping on persistent failures.
When it happens
Trigger: FindNextPrinterChangeNotification failing because the change handle became invalid (spooler restart, handle closed), the options/pointer arguments are malformed, or access was revoked while monitoring.
Common situations: Print Spooler service restarted or crashed while the monitor was running; long-running monitors losing their registration; passing an options struct the API rejects on subsequent calls.
Related errors
- Failed to get a change handle
- Failed to access the print server
- Win32Exception (error code from GetLastError after EnumJobs)
- Win32Exception (error code from GetLastError after…
- Could not set proxy blanket.
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/74303523199d4b52.
Report an issue: GitHub.
Appendix: source
Thrown at contrib/w32printing/src/com/sun/jna/platform/win32/Win32SpoolMonitor.java:152
try {
while (true) {
Kernel32.INSTANCE.WaitForSingleObject(
changeNotificationsHandle,
WinBase.INFINITE);
DWORDByReference change =
new DWORDByReference();
PointerByReference infoPointer = new PointerByReference();
success =
Winspool.INSTANCE.FindNextPrinterChangeNotification(
changeNotificationsHandle,
change,
options,
infoPointer);
if (!success) {
int errorCode = Kernel32.INSTANCE.GetLastError();
throw new RuntimeException("Failed to get printer " +
"change notification - " + errorCode);
}
System.out.println("Change - " +
String.format("0x%08X", change.getValue().longValue()));
if (infoPointer.getValue() != null) {
PRINTER_NOTIFY_INFO info =
Structure.newInstance(PRINTER_NOTIFY_INFO.class,
infoPointer.getValue());
info.read();
try {
if ((info.Flags & PRINTER_NOTIFY_INFO_DISCARDED) > 0) {
System.out.println("Some information was " +
"discarded");
}
View on GitHub (pinned to d036ad9781)