java-native-access/jna · error · IllegalArgumentException

Callback method is inaccessible, make sure the interface is

Error message

Callback method is inaccessible, make sure the interface is public: <callbackMethod>

What it means

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.

Source

Thrown at src/com/sun/jna/CallbackReference.java:555

                toNative = NativeMappedConverter.getInstance(returnType);
            }
            else if (mapper != null) {
                toNative = mapper.getToNativeConverter(returnType);
            }
            for (int i=0;i < fromNative.length;i++) {
                if (NativeMapped.class.isAssignableFrom(argTypes[i])) {
                    fromNative[i] = new NativeMappedConverter(argTypes[i]);
                }
                else if (mapper != null) {
                    fromNative[i] = mapper.getFromNativeConverter(argTypes[i]);
                }
            }
            if (!callbackMethod.isAccessible()) {
                try {
                    callbackMethod.setAccessible(true);
                }
                catch(SecurityException e) {
                    throw new IllegalArgumentException("Callback method is inaccessible, make sure the interface is public: " + callbackMethod);
                }
            }
        }

        public Callback getCallback() {
            return CallbackReference.this.getCallback();
        }

        private Object invokeCallback(Object[] args) {
            Class<?>[] paramTypes = callbackMethod.getParameterTypes();
            Object[] callbackArgs = new Object[args.length];

            // convert basic supported types to appropriate Java parameter types
            for (int i=0;i < args.length;i++) {
                Class<?> type = paramTypes[i];
                Object arg = args[i];
                if (fromNative[i] != null) {
                    FromNativeContext context =

View on GitHub (pinned to d036ad9781)

Solutions

  1. Declare the callback interface and its method public (make nested interfaces public static).
  2. If using JPMS, open/export the package: add 'exports com.example.callbacks;' or 'opens com.example.callbacks;' to module-info.java.
  3. If a SecurityManager is present, grant the JNA codebase runtime permission suppressAccessChecks, or run without the security manager in trusted environments.
  4. In OSGi, add the required AllPermission/-suppressAccessChecks via bundle policy or use fragment/extender patterns giving JNA access.

Example fix

// before
interface SecretCb extends Callback { void invoke(int code); } // package-private
// after
public interface SecretCb extends Callback { void invoke(int code); }
// JPMS alternative: add to module-info.java
exports com.example.callbacks;
Defensive patterns

Strategy: validation

Validate before calling

static void requireAccessibleCallback(Method m) {
    if (!java.lang.reflect.Modifier.isPublic(m.getDeclaringClass().getModifiers()))
        throw new IllegalArgumentException("Callback interface must be public: " + m.getDeclaringClass());
}

Type guard

static boolean isPubliclyAccessible(Class<?> iface) {
    return java.lang.reflect.Modifier.isPublic(iface.getModifiers());
}

Try / catch

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; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12). Data as JSON: /api/errors/c5e3270dd52ba779. Report an issue: GitHub.