{"record":{"id":"74303523199d4b52","repo":"java-native-access/jna","slug":"failed-to-get-printer-change-notification-errorcode","errorCode":null,"errorMessage":"Failed to get printer change notification - <errorCode>","messagePattern":"Failed to get printer change notification - <errorCode>","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"contrib/w32printing/src/com/sun/jna/platform/win32/Win32SpoolMonitor.java","lineNumber":152,"sourceCode":"\n            try {\n                while (true) {\n                    Kernel32.INSTANCE.WaitForSingleObject(\n                        changeNotificationsHandle,\n                        WinBase.INFINITE);\n\n                    DWORDByReference change =\n                        new DWORDByReference();\n                    PointerByReference infoPointer = new PointerByReference();\n                    success =\n                        Winspool.INSTANCE.FindNextPrinterChangeNotification(\n                            changeNotificationsHandle,\n                            change,\n                            options,\n                            infoPointer);\n                    if (!success) {\n                        int errorCode = Kernel32.INSTANCE.GetLastError();\n                        throw new RuntimeException(\"Failed to get printer \" +\n                            \"change notification - \" + errorCode);\n                    }\n\n                    System.out.println(\"Change - \" +\n                        String.format(\"0x%08X\", change.getValue().longValue()));\n\n                    if (infoPointer.getValue() != null) {\n                        PRINTER_NOTIFY_INFO info =\n                            Structure.newInstance(PRINTER_NOTIFY_INFO.class,\n                                infoPointer.getValue());\n                        info.read();\n\n                        try {\n                            if ((info.Flags & PRINTER_NOTIFY_INFO_DISCARDED) > 0) {\n                                System.out.println(\"Some information was \" +\n                                    \"discarded\");\n                            }\n","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/java-native-access/jna/blob/d036ad9781adad4b66693e8fa7098e4ac665e0a3/contrib/w32printing/src/com/sun/jna/platform/win32/Win32SpoolMonitor.java#L134-L170","documentation":"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.","triggerScenarios":"FindNextPrinterChangeNotification failing because the change handle became invalid (spooler restart, handle closed), the options/pointer arguments are malformed, or access was revoked while monitoring.","commonSituations":"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.","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."],"exampleFix":"// before\nwhile (true) { ... FindNextPrinterChangeNotification(...); }\n// after\nwhile (running) {\n    try {\n        monitorOnce();\n    } catch (RuntimeException e) {\n        LOG.warn(\"Change notification failed, re-registering\", e);\n        closeHandles();\n        reOpenAndRegister();\n    }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"boolean ok = Winspool.INSTANCE.FindNextPrinterChangeNotification(handle, change, options, infoPointer);\nif (!ok) {\n    int err = Kernel32.INSTANCE.GetLastError();\n    if (err == W32Errors.ERROR_INVALID_HANDLE) { reRegisterMonitor(); }\n}","preventionTips":["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."],"tags":["windows","printing","handle","runtime-exception"],"backgroundTag":"api-error-response","analyzedSha":"d036ad9781adad4b66693e8fa7098e4ac665e0a3","analyzedAt":"2026-09-12T06:50:59.239Z","contentChangedAt":"2026-09-12T06:50:59.239Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}