{"record":{"id":"358cbb91d2f574b5","repo":"java-native-access/jna","slug":"expected-gettokeninformation-to-fail-with-error-insufficient","errorCode":null,"errorMessage":"Expected GetTokenInformation to fail with ERROR_INSUFFICIENT_BUFFER","messagePattern":"Expected GetTokenInformation to fail with ERROR_INSUFFICIENT_BUFFER","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java","lineNumber":443,"sourceCode":"    public static Account getAccountBySid(String systemName, String sidString) {\n        return getAccountBySid(systemName, new PSID(convertStringSidToSid(sidString)));\n    }\n\n    /**\n     * This function returns the groups associated with a security token, such\n     * as a user token.\n     *\n     * @param hToken\n     *            Token.\n     * @return Token groups.\n     */\n    public static Account[] getTokenGroups(HANDLE hToken) {\n        // get token group information size\n        IntByReference tokenInformationLength = new IntByReference();\n        if (Advapi32.INSTANCE.GetTokenInformation(hToken,\n                WinNT.TOKEN_INFORMATION_CLASS.TokenGroups, null, 0,\n                tokenInformationLength)) {\n            throw new RuntimeException(\n                    \"Expected GetTokenInformation to fail with ERROR_INSUFFICIENT_BUFFER\");\n        }\n        int rc = Kernel32.INSTANCE.GetLastError();\n        if (rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {\n            throw new Win32Exception(rc);\n        }\n        // get token group information\n        WinNT.TOKEN_GROUPS groups = new WinNT.TOKEN_GROUPS(\n                tokenInformationLength.getValue());\n        if (!Advapi32.INSTANCE.GetTokenInformation(hToken,\n                WinNT.TOKEN_INFORMATION_CLASS.TokenGroups, groups,\n                tokenInformationLength.getValue(), tokenInformationLength)) {\n            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());\n        }\n        ArrayList<Account> userGroups = new ArrayList<>();\n        // make array of names\n        for (SID_AND_ATTRIBUTES sidAndAttribute : groups.getGroups()) {\n            Account group;","sourceCodeStart":425,"sourceCodeEnd":461,"githubUrl":"https://github.com/java-native-access/jna/blob/d036ad9781adad4b66693e8fa7098e4ac665e0a3/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java#L425-L461","documentation":"getTokenGroups sizes the TOKEN_GROUPS buffer by calling GetTokenInformation with a null buffer; per the Win32 contract this must fail with ERROR_INSUFFICIENT_BUFFER while writing the required size into tokenInformationLength. This RuntimeException signals the contract violation: the probe call unexpectedly succeeded. Like error [80], it points to an OS/JNA mapping mismatch rather than caller input.","triggerScenarios":"Advapi32.INSTANCE.GetTokenInformation(hToken, TokenGroups, null, 0, tokenInformationLength) returns TRUE on the sizing call, triggering the RuntimeException at Advapi32Util.java:443; reached directly or via getCurrentUserGroups.","commonSituations":"Non-Windows or unusual Windows builds where the null-buffer probe succeeds; tests with a mocked Advapi32 that ignores the null-buffer convention; JNA version mismatches between jna and jna-platform.","solutions":["Upgrade to the latest com.sun.jna:jna and jna-platform so the GetTokenInformation mapping matches your OS","Ensure tests/mocks model the real API: null buffer + ReturnLength must yield ERROR_INSUFFICIENT_BUFFER, not success","Check that hToken is a real token handle from Advapi32.INSTANCE.OpenProcessToken/OpenThreadToken, not a fabricated HANDLE value","As a workaround, preallocate a generous TOKEN_GROUPS buffer and call GetTokenInformation once, tolerating ERROR_INSUFFICIENT_BUFFER"],"exampleFix":"// before\nAccount[] groups = Advapi32Util.getTokenGroups(hToken);\n// after - ensure the handle is genuine first\nIntByReference tokType = new IntByReference();\nif (!Advapi32.INSTANCE.OpenProcessToken(Kernel32.INSTANCE.GetCurrentProcess(),\n        WinNT.TOKEN_QUERY, hToken)) {\n    throw new Win32Exception(Kernel32.INSTANCE.GetLastError());\n}\nAccount[] groups = Advapi32Util.getTokenGroups(hToken);","handlingStrategy":"validation","validationCode":"HANDLEByReference hRef = new HANDLEByReference();\nif (!Advapi32.INSTANCE.OpenProcessToken(Kernel32.INSTANCE.GetCurrentProcess(),\n        WinNT.TOKEN_QUERY, hRef)) {\n    throw new Win32Exception(Kernel32.INSTANCE.GetLastError());\n}\nif (!Platform.isWindows()) {\n    throw new UnsupportedOperationException(\"token APIs require Windows\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    Account[] groups = Advapi32Util.getTokenGroups(hToken);\n} catch (RuntimeException e) {\n    // probe-contract violation: log environment details, report to JNA\n    throw new IllegalStateException(\"GetTokenInformation sizing call succeeded unexpectedly\", e);\n}","preventionTips":["Keep jna and jna-platform versions aligned and current","Acquire the token via OpenProcessToken/OpenThreadToken with TOKEN_QUERY","Prefer Advapi32Util.getCurrentUserGroups() over manual handle management","Ensure test mocks replicate the ERROR_INSUFFICIENT_BUFFER sizing contract"],"tags":["windows","win32","jna","token","internal-invariant"],"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"}