{"record":{"id":"a69190704034c034","repo":"java-native-access/jna","slug":"mismatched-allocated-x-vs-received-devices-count-y","errorCode":null,"errorMessage":"Mismatched allocated (X) vs. received devices count (Y)","messagePattern":"Mismatched allocated \\(X\\) vs\\. received devices count \\(Y\\)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"contrib/platform/src/com/sun/jna/platform/win32/User32Util.java","lineNumber":109,"sourceCode":"    public static final List<RAWINPUTDEVICELIST> GetRawInputDeviceList() {\n        IntByReference puiNumDevices = new IntByReference(0);\n        RAWINPUTDEVICELIST placeholder = new RAWINPUTDEVICELIST();\n        int cbSize = placeholder.sizeof();\n        // first call is with NULL so we query the expected number of devices\n        int returnValue = User32.INSTANCE.GetRawInputDeviceList(null, puiNumDevices, cbSize);\n        if (returnValue != 0) {\n            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());\n        }\n\n        int deviceCount = puiNumDevices.getValue();\n        RAWINPUTDEVICELIST[] records = (RAWINPUTDEVICELIST[]) placeholder.toArray(deviceCount);\n        returnValue = User32.INSTANCE.GetRawInputDeviceList(records, puiNumDevices, cbSize);\n        if (returnValue == (-1)) {\n            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());\n        }\n\n        if (returnValue != records.length) {\n            throw new IllegalStateException(\"Mismatched allocated (\" + records.length + \") vs. received devices count (\" + returnValue + \")\");\n        }\n\n        return Arrays.asList(records);\n    }\n\n    /**\n     * Helper class, that runs a windows message loop as a seperate thread.\n     *\n     * This is intended to be used in conjunction with APIs, that need a\n     * spinning message loop. One example for this are the DDE functions, that\n     * can only be used if a message loop is present.\n     *\n     * To enable interaction with the mainloop the MessageLoopThread allows to\n     * dispatch callables into the mainloop and let these Callables be invoked\n     * on the message thread.\n     *\n     * This implies, that the Callables should block the loop as short as possible.\n     */","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/java-native-access/jna/blob/d036ad9781adad4b66693e8fa7098e4ac665e0a3/contrib/platform/src/com/sun/jna/platform/win32/User32Util.java#L91-L127","documentation":"GetRawInputDeviceList was called with a pre-allocated RAWINPUTDEVICELIST array whose size was obtained via a first (count-query) call. If the actual number of devices returned differs from the array length, JNA throws this IllegalStateException because the buffer is inconsistent with the returned count, and returning partial/garbage records would be unsafe.","triggerScenarios":"Calling User32Util.GetRawInputDeviceList when raw input devices are plugged in or removed between the count-query call and the array-allocation call, so GetRawInputDeviceList returns a count different from the previously queried number.","commonSituations":"Hot-plugging/unplugging HID devices (mouse, keyboard, gamepad) between the two native calls; concurrent processes enumerating devices; virtualized/RDP environments where device lists change dynamically.","solutions":["Catch the IllegalStateException and simply retry GetRawInputDeviceList — the second call re-queries the count and will usually succeed","Call the method again inside a small retry loop (2-3 attempts) since the mismatch is inherently transient","Avoid hot-plugging devices during enumeration in automated/test setups"],"exampleFix":"// before\nList<RAWINPUTDEVICELIST> devices = User32Util.GetRawInputDeviceList();\n// after\nList<RAWINPUTDEVICELIST> devices;\ntry {\n    devices = User32Util.GetRawInputDeviceList();\n} catch (IllegalStateException e) {\n    devices = User32Util.GetRawInputDeviceList(); // retry: device list changed mid-query\n}","handlingStrategy":"retry","validationCode":"// No pre-validation possible; just wrap the call in a bounded retry\nList<RAWINPUTDEVICELIST> list;\nfor (int i = 0; i < 3; i++) {\n    try { list = User32Util.GetRawInputDeviceList(); break; }\n    catch (IllegalStateException e) { if (i == 2) throw e; }\n}","typeGuard":null,"tryCatchPattern":"try {\n    devices = User32Util.GetRawInputDeviceList();\n} catch (IllegalStateException e) {\n    devices = User32Util.GetRawInputDeviceList(); // transient race\n}","preventionTips":["Always wrap this call in a small retry loop — device counts can change between the two native calls","Avoid enumerating during hot-plug-heavy scenarios (device driver installs)","Log and retry rather than crashing; the mismatch is inherently transient"],"tags":["win32","raw-input","race-condition"],"backgroundTag":"internal-invariant-violation","analyzedSha":"d036ad9781adad4b66693e8fa7098e4ac665e0a3","analyzedAt":"2026-09-12T06:50:59.239Z","contentChangedAt":"2026-09-12T06:50:59.239Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}