java-native-access/jna · error · java.lang.IllegalStateException
This method must be called from the static initializer of a
Error message
This method must be called from the static initializer of a class
What it means
When Native.register() infers the calling class via the SecurityManager getClassContext mechanism, the returned context array must contain the whole stack; index 3 holds the expected caller. If the stack is shallower than 4 frames, the call is not happening where JNA requires — the static initializer of the class being registered — so it throws this IllegalStateException.
Source
Thrown at src/com/sun/jna/Native.java:1640
} catch (Throwable ex) {
LOG.log(Level.WARNING, "Failed to invoke StackWalker#getInstance or StackWalker#walk", ex);
}
}
if (securityManagerExposerConstructor != null) {
Class<?>[] context = null;
try {
Object securityManagerExposer = securityManagerExposerConstructor.newInstance();
context = (Class<?>[]) securityManagerGetClassContext.invoke(securityManagerExposer);
} catch (Throwable ex) {
LOG.log(Level.WARNING, "Failed to invoke SecurityManagerExposer#<init> or SecurityManagerExposer#getClassContext", ex);
}
if (context == null) {
throw new IllegalStateException("The SecurityManager implementation on this platform is broken; you must explicitly provide the class to register");
}
if (context.length < 4) {
throw new IllegalStateException("This method must be called from the static initializer of a class");
}
return context[3];
}
throw new IllegalStateException("Neither the StackWalker, nor the SecurityManager based getCallingClass implementation are useable; you must explicitly provide the class to register");
}
/**
* Set a thread initializer for the given callback.
* @param cb The callback to invoke
* @param initializer The thread initializer indicates desired thread configuration when the
* given Callback is invoked on a native thread not yet attached to the VM.
*/
public static void setCallbackThreadInitializer(Callback cb, CallbackThreadInitializer initializer) {
CallbackReference.setCallbackThreadInitializer(cb, initializer);
}
private static final Map<Class<?>, long[]> registeredClasses = new WeakHashMap<>();View on GitHub (pinned to d036ad9781)
Solutions
- Place Native.register() directly in the static initializer: static { Native.register("lib"); }.
- Alternatively pass the class explicitly: Native.register("lib", MyClass.class), removing the frame-depth requirement.
- Avoid delegating registration to another class's method when relying on inference; each mapped class must register itself.
- If called via reflection, ensure sufficient call depth or use the explicit-class overload.
Example fix
// before
class MyLib {
static void init() { Native.register("mylib"); }
static { init(); } // extra frames: register not called from <clinit> at depth 3
}
// after
class MyLib {
static { Native.register("mylib"); }
} Defensive patterns
Strategy: type-guard
Validate before calling
// ensure registration happens in <clinit>, not via helper methods
static final boolean REGISTERED;
static {
StackTraceElement[] st = new Throwable().getStackTrace();
if (st.length < 4 || !"<clinit>".equals(st[1].getMethodName())) {
throw new IllegalStateException("Call Native.register only from the static initializer");
}
Native.register("mylib");
REGISTERED = true;
} Try / catch
try {
Native.register("mylib");
} catch (IllegalStateException e) {
if (e.getMessage().contains("static initializer")) {
Native.register("mylib", MyLib.class);
} else { throw e; }
} Prevention
- Put Native.register inline in the static initializer — never behind a method call.
- Prefer the explicit-class overload to eliminate frame-depth coupling.
- Do not invoke register through reflection or MethodHandles.
- Code-review rule: register() calls live only in static blocks.
When it happens
Trigger: Calling Native.register() (without an explicit class) from instance code, a regular method, a nested helper, or any frame depth where fewer than 4 stack frames exist, instead of the class's static initializer.
Common situations: Lazy initialization of the native library inside a getter or constructor, invoking register via reflection/MethodHandle with a truncated stack, or refactoring the static block into a shared utility method.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Can't determine class with native methods from the current c
- Error looking up CallbackProxy.callback() method
- Error loading DLLCallback class
- The SecurityManager implementation on this platform is broke
- Neither the StackWalker, nor the SecurityManager based getCa
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/1b43afc5b88c6459.
Report an issue: GitHub.