java-native-access/jna · error · IllegalArgumentException
Callback type must be an interface
Error message
Callback type must be an interface
What it means
IllegalArgumentException thrown by CallbackReference.getCallback(Class, Pointer, boolean) when an existing native Pointer is being re-associated with a callback, but the given Class is not an interface. JNA callbacks must be declared as interfaces (extending com.sun.jna.Callback) because JNA generates a dynamic proxy that implements them; a concrete class cannot be proxied this way.
Source
Thrown at src/com/sun/jna/CallbackReference.java:160
/** Return a Callback associated with the given function pointer.
* If the pointer refers to a Java callback trampoline, return the original
* Java Callback. Otherwise, return a proxy to the native function
* pointer.
* @throws IllegalStateException if the given pointer has already been
* mapped to a callback of a different type.
*/
public static Callback getCallback(Class<?> type, Pointer p) {
return getCallback(type, p, false);
}
private static Callback getCallback(Class<?> type, Pointer p, boolean direct) {
if (p == null) {
return null;
}
if (!type.isInterface())
throw new IllegalArgumentException("Callback type must be an interface");
Map<Callback, CallbackReference> map = direct ? directCallbackMap : callbackMap;
synchronized(pointerCallbackMap) {
Reference<Callback>[] array = pointerCallbackMap.get(p);
Callback cb = getTypeAssignableCallback(type, array);
if (cb != null) {
return cb;
}
cb = createCallback(type, p);
pointerCallbackMap.put(p, addCallbackToArray(cb,array));
// No CallbackReference for this callback
map.remove(cb);
return cb;
}
}
private static Callback getTypeAssignableCallback(Class<?> type, Reference<Callback>[] array) {
if (array != null) {View on GitHub (pinned to d036ad9781)
Solutions
- Declare the callback as an interface that extends com.sun.jna.Callback and pass that interface's Class (e.g. MyCallback.class), not the implementing object's class.
- If you have an instance, get the interface via a helper that finds the Callback-derived interface (JNA's findCallbackClass logic) instead of using obj.getClass().
- Convert abstract-class callbacks to interface-based declarations, with the implementation as a separate class or anonymous class.
Example fix
// before
class MyHandler implements MyCallback { public void callback(Object[] args) {} }
Callback cb = CallbackReference.getCallback(handler.getClass(), ptr); // IllegalArgumentException
// after
interface MyHandler extends Callback { void callback(Object[] args); }
Callback cb = CallbackReference.getCallback(MyHandler.class, ptr); Defensive patterns
Strategy: type-guard
Validate before calling
static void requireCallbackInterface(Class<?> t) {
if (t == null || !t.isInterface() || !Callback.class.isAssignableFrom(t))
throw new IllegalArgumentException(t + " must be an interface extending Callback");
} Type guard
static boolean isCallbackInterface(Class<?> t) {
return t != null && t.isInterface() && Callback.class.isAssignableFrom(t);
} Try / catch
try { cb = CallbackReference.getCallback(type, ptr); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Pass the callback INTERFACE class, not the impl class", e); } Prevention
- Always declare callbacks as interfaces extending com.sun.jna.Callback.
- Never pass getClass(); pass the interface Class literal.
- Avoid abstract-class callbacks; refactor to interfaces.
- Enable IDE linting for JNA callback declarations.
When it happens
Trigger: Calling CallbackReference.getCallback(type, pointer) — e.g. via Native.getCallback or during structure-to-callback conversion — with a Class object that is a concrete class (or abstract class) rather than an interface, typically obtained via getClass() instead of the callback interface.
Common situations: Passing obj.getClass() of a class that implements a callback instead of the interface Class; defining a callback as an abstract class implementing Callback and calling native code with it; library utilities re-mapping pointers to callbacks using the wrong Class object.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- <type> is not derived from com.sun.jna.Callback
- Structure Callback field '" + field.getName() + "' must be a
- Unexpected registry type + lpType.getValue() + , expected RE
- Unexpected registry type + lpType.getValue() + , expected RE
- Unexpected registry type {}, expected REG_SZ
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/7a37462384f290aa.
Report an issue: GitHub.