{"record":{"id":"c5e3270dd52ba779","repo":"java-native-access/jna","slug":"callback-method-is-inaccessible-make-sure-the-interface-is","errorCode":null,"errorMessage":"Callback method is inaccessible, make sure the interface is public: <callbackMethod>","messagePattern":"Callback method is inaccessible, make sure the interface is public: <callbackMethod>","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/com/sun/jna/CallbackReference.java","lineNumber":555,"sourceCode":"                toNative = NativeMappedConverter.getInstance(returnType);\n            }\n            else if (mapper != null) {\n                toNative = mapper.getToNativeConverter(returnType);\n            }\n            for (int i=0;i < fromNative.length;i++) {\n                if (NativeMapped.class.isAssignableFrom(argTypes[i])) {\n                    fromNative[i] = new NativeMappedConverter(argTypes[i]);\n                }\n                else if (mapper != null) {\n                    fromNative[i] = mapper.getFromNativeConverter(argTypes[i]);\n                }\n            }\n            if (!callbackMethod.isAccessible()) {\n                try {\n                    callbackMethod.setAccessible(true);\n                }\n                catch(SecurityException e) {\n                    throw new IllegalArgumentException(\"Callback method is inaccessible, make sure the interface is public: \" + callbackMethod);\n                }\n            }\n        }\n\n        public Callback getCallback() {\n            return CallbackReference.this.getCallback();\n        }\n\n        private Object invokeCallback(Object[] args) {\n            Class<?>[] paramTypes = callbackMethod.getParameterTypes();\n            Object[] callbackArgs = new Object[args.length];\n\n            // convert basic supported types to appropriate Java parameter types\n            for (int i=0;i < args.length;i++) {\n                Class<?> type = paramTypes[i];\n                Object arg = args[i];\n                if (fromNative[i] != null) {\n                    FromNativeContext context =","sourceCodeStart":537,"sourceCodeEnd":573,"githubUrl":"https://github.com/java-native-access/jna/blob/d036ad9781adad4b66693e8fa7098e4ac665e0a3/src/com/sun/jna/CallbackReference.java#L537-L573","documentation":"IllegalArgumentException thrown by DefaultCallbackProxy's constructor when callbackMethod.isAccessible() is false and Method.setAccessible(true) fails with a SecurityException. JNA's generated proxy must invoke the callback method reflectively; if a SecurityManager or module encapsulation (JPMS strong encapsulation) blocks access to a non-public callback interface, registration of the callback cannot proceed. The message explicitly hints that making the interface public usually fixes it.","triggerScenarios":"Defining a callback interface (or the specific callback method) as non-public (package-private/nested without public) while a SecurityManager policy or Java module system denies setAccessible on it; running under restrictive containers (app servers, OSGi) where JNA's classloader lacks suppressAccessChecks permission; Java 9+ modules hiding a non-exported package containing the callback interface.","commonSituations":"Package-private callback interfaces inside library code under a SecurityManager; callback interfaces defined inside a non-open JPMS module; OSGi bundles without the required (suppressAccessChecks) DoPrivileged permission; sandboxed plugin environments.","solutions":["Declare the callback interface and its method public (make nested interfaces public static).","If using JPMS, open/export the package: add 'exports com.example.callbacks;' or 'opens com.example.callbacks;' to module-info.java.","If a SecurityManager is present, grant the JNA codebase runtime permission suppressAccessChecks, or run without the security manager in trusted environments.","In OSGi, add the required AllPermission/-suppressAccessChecks via bundle policy or use fragment/extender patterns giving JNA access."],"exampleFix":"// before\ninterface SecretCb extends Callback { void invoke(int code); } // package-private\n// after\npublic interface SecretCb extends Callback { void invoke(int code); }\n// JPMS alternative: add to module-info.java\nexports com.example.callbacks;","handlingStrategy":"validation","validationCode":"static void requireAccessibleCallback(Method m) {\n    if (!java.lang.reflect.Modifier.isPublic(m.getDeclaringClass().getModifiers()))\n        throw new IllegalArgumentException(\"Callback interface must be public: \" + m.getDeclaringClass());\n}","typeGuard":"static boolean isPubliclyAccessible(Class<?> iface) {\n    return java.lang.reflect.Modifier.isPublic(iface.getModifiers());\n}","tryCatchPattern":"try { registerCallback(cb); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"make sure the interface is public\")) { /* make interface public or open the JPMS package */ } throw e; }","preventionTips":["Make callback interfaces (and nested ones) public static.","In JPMS, export/open packages containing callbacks.","Grant suppressAccessChecks to JNA when a SecurityManager is mandatory.","Test callback registration under the same security/module settings as production."],"tags":["jna","callback","accessibility","reflection","security-manager"],"backgroundTag":"permission-denied","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"}