java-native-access/jna · error · java.lang.IllegalArgumentException

Can't determine class with native methods from the current c

Error message

Can't determine class with native methods from the current context (cls)

What it means

Native.register() can infer the class containing native method declarations from the call stack when it is not passed explicitly. After trying the caller-class and ClassLoader-resource heuristics, JNA gives up when no class with native methods can be determined from the current context, and throws this IllegalArgumentException mentioning the (null or wrong) cls it found.

Source

Thrown at src/com/sun/jna/Native.java:1588

    /** Find the nearest enclosing class with native methods. */
    static Class<?> findDirectMappedClass(Class<?> cls) {
        Method[] methods = cls.getDeclaredMethods();
        for (Method m : methods) {
            if ((m.getModifiers() & Modifier.NATIVE) != 0) {
                return cls;
            }
        }
        int idx = cls.getName().lastIndexOf("$");
        if (idx != -1) {
            String name = cls.getName().substring(0, idx);
            try {
                return findDirectMappedClass(Class.forName(name, true, cls.getClassLoader()));
            } catch(ClassNotFoundException e) {
                // ignored
            }
        }
        throw new IllegalArgumentException("Can't determine class with native methods from the current context (" + cls + ")");
    }

    /** Try to determine the class context in which a {@link #register(String)} call
        was made.
    */
    static Class<?> getCallingClass() {
        // This method makes the assumption that it is only called from register
        // and unregister methods of this class. It is further assumed, that
        // these two methods are called from a static initialized block or from
        // a method of the class to be registered.
        //
        // There are two approaches taken to find the right stack frame:
        // - on modern VMs the StackWalker API is used and the first two entries
        //   are skipped. The stack at the time of calling is:
        //   0. Stackframe: #getCallingClass
        //   1. Stackframe: #register or #unregister
        //   2. Stackframe: method of outer caller
        //   the last element is the right one

View on GitHub (pinned to d036ad9781)

Solutions

  1. Pass the class explicitly: Native.register(MyLib.class) (or Native.register(libName, MyLib.class)) instead of relying on inference.
  2. Move the Native.register call into the static initializer of the class that declares the native methods.
  3. If using obfuscation/minification (ProGuard/R8), keep the registering class name and its native methods.
  4. Use the overload taking a NativeLibrary instance with an explicit class to bypass stack inspection entirely.

Example fix

// before
static void init() { Native.register(); } // inferred context is wrong/null

// after
static void init() { Native.register(MyNativeLib.class); }
Defensive patterns

Strategy: validation

Validate before calling

if (cls == null || cls.getDeclaredMethods().length == 0) {
    throw new IllegalArgumentException("Native.register needs an explicit class that declares native methods");
}
Native.register(cls);

Try / catch

try {
    Native.register();
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Can't determine class")) {
        Native.register(MyNativeLib.class);
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling Native.register() with no explicit Class argument from code that is not a static initializer of the interface/implementation class — e.g. from a helper method, factory, lambda, reflection frame, or a relocated/obfuscated stack where the inferred class has no native methods.

Common situations: Registering in a non-standard bootstrap path (Spring bean factory method, OSGi bundle classloader, GraalVM native-image with stripped stacks), or calling register indirectly so the 'cls' heuristic resolves to the wrong class.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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