{"record":{"id":"edc78a7e75bf8e19","repo":"java-native-access/jna","slug":"win32exception-from-getlasterror-after-module32nextw-failed","errorCode":null,"errorMessage":"Win32Exception from GetLastError after Module32NextW failed with unexpected error","messagePattern":"Win32Exception from GetLastError after Module32NextW failed with unexpected error","errorType":"error_code","errorClass":"Win32Exception","httpStatus":null,"severity":"error","filePath":"contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java","lineNumber":1197,"sourceCode":"            if (!Kernel32.INSTANCE.Module32FirstW(snapshot, first)) {\n                throw new Win32Exception(Kernel32.INSTANCE.GetLastError());\n            }\n\n            List<Tlhelp32.MODULEENTRY32W> modules = new ArrayList<>();\n            modules.add(first);\n\n            Tlhelp32.MODULEENTRY32W next = new Tlhelp32.MODULEENTRY32W();\n            while (Kernel32.INSTANCE.Module32NextW(snapshot, next)) {\n                modules.add(next);\n                next = new Tlhelp32.MODULEENTRY32W();\n            }\n\n            int lastError = Kernel32.INSTANCE.GetLastError();\n            // if we got a false from Module32Next,\n            // check to see if it returned false because we're genuinely done\n            // or if something went wrong.\n            if (lastError != W32Errors.ERROR_SUCCESS && lastError != W32Errors.ERROR_NO_MORE_FILES) {\n                throw new Win32Exception(lastError);\n            }\n\n            return modules;\n        } catch (final Win32Exception e) {\n            throw we = e; // re-throw to avoid return value!\n        } finally {\n            cleanUp(snapshot, we);\n        }\n    }\n\n    /**\n     * Expands environment-variable strings and replaces them with the values\n     * defined for the current user.\n     *\n     * @param input A string that contains one or more environment-variable\n     *              strings in the form: %variableName%. For each such\n     *              reference, the %variableName% portion is replaced with the\n     *              current value of that environment variable.","sourceCodeStart":1179,"sourceCodeEnd":1215,"githubUrl":"https://github.com/java-native-access/jna/blob/d036ad9781adad4b66693e8fa7098e4ac665e0a3/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java#L1179-L1215","documentation":"Kernel32Util.getModules throws this Win32Exception when Module32NextW returns false with a last-error other than ERROR_SUCCESS (0) or ERROR_NO_MORE_FILES (18). Those two codes mean the iteration finished normally; any other code is treated as a genuine failure during module-list iteration and is wrapped in a Win32Exception.","triggerScenarios":"Calling Kernel32Util.getModules(processID) where the module iteration fails partway with an unexpected native error — the target process was modified/unloaded modules mid-iteration, the snapshot handle became invalid, or an access violation in the toolhelp walk surfaces as a real error code.","commonSituations":"Inspecting a rapidly starting/exiting process whose module list changes during enumeration, hooking/injection tools mutating modules concurrently, scanning many PIDs in a loop and hitting transient states.","solutions":["Catch Win32Exception and treat the partially collected module list as best-effort output","Filter out unexpected transient codes (e.g. ERROR_PARTIAL_COPY 299) and retry the snapshot","Retry getModules once or twice for PIDs known to be short-lived","Check errorCode to distinguish real failures (6=invalid handle) from iteration completion"],"exampleFix":"// before\nList<Tlhelp32.MODULEENTRY32W> mods = Kernel32Util.getModules(pid);\n// after\nList<Tlhelp32.MODULEENTRY32W> mods;\ntry {\n    mods = Kernel32Util.getModules(pid);\n} catch (Win32Exception e) {\n    if (e.getErrorCode().intValue() == 299) { // ERROR_PARTIAL_COPY: process changed mid-scan\n        mods = Kernel32Util.getModules(pid); // single retry\n    } else {\n        throw e;\n    }\n}","handlingStrategy":"retry","validationCode":"// ensure PID is still alive to reduce mid-iteration teardown races\nif (!pidAlive(pid)) return Collections.emptyList();","typeGuard":"null","tryCatchPattern":"List<Tlhelp32.MODULEENTRY32W> mods;\ntry {\n    mods = Kernel32Util.getModules(pid);\n} catch (Win32Exception e) {\n    if (e.getErrorCode().intValue() == 299) { // ERROR_PARTIAL_COPY — transient\n        mods = Kernel32Util.getModules(pid);\n    } else {\n        throw e;\n    }\n}","preventionTips":["Retry snapshots for PIDs whose module list may change mid-iteration","Filter expected transient codes (ERROR_PARTIAL_COPY 299) from hard failures","Use the partially returned data when best-effort output is acceptable","Rate-limit scans of many PIDs to reduce contention with process churn"],"tags":["win32","jni","native","processes","iteration"],"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"}