java-native-access/jna · error · IllegalArgumentException
Callback return type <returnType> requires custom type conve
Error message
Callback return type <returnType> requires custom type conversion
What it means
IllegalArgumentException thrown while registering a native callback when the callback method's RETURN type does not map to an allowable native type. JNA must convert the Java return value back to a native register value; only primitives, void, Pointer, Structure, String/WString and similar mappable types are supported. Without a TypeMapper/custom converter, any other return type fails registration.
Source
Thrown at src/com/sun/jna/CallbackReference.java:321
}
ToNativeConverter tn = mapper.getToNativeConverter(returnType);
if (tn != null) {
returnType = tn.nativeType();
}
}
for (int i=0;i < nativeParamTypes.length;i++) {
nativeParamTypes[i] = getNativeType(nativeParamTypes[i]);
if (!isAllowableNativeType(nativeParamTypes[i])) {
String msg = "Callback argument " + nativeParamTypes[i]
+ " requires custom type conversion";
throw new IllegalArgumentException(msg);
}
}
returnType = getNativeType(returnType);
if (!isAllowableNativeType(returnType)) {
String msg = "Callback return type " + returnType
+ " requires custom type conversion";
throw new IllegalArgumentException(msg);
}
int flags = DLL_CALLBACK_CLASS != null
&& DLL_CALLBACK_CLASS.isInstance(callback)
? Native.CB_OPTION_IN_DLL : 0;
peer = Native.createNativeCallback(proxy, PROXY_CALLBACK_METHOD,
nativeParamTypes, returnType,
callingConvention, flags,
encoding);
}
cbstruct = peer != 0 ? new Pointer(peer) : null;
if(peer != 0) {
allocatedMemory.put(peer, new WeakReference<>(this));
cleanable = Cleaner.getCleaner().register(this, new CallbackReferenceDisposer(cbstruct));
}
}
private Class<?> getNativeType(Class<?> cls) {
if (Structure.class.isAssignableFrom(cls)) {View on GitHub (pinned to d036ad9781)
Solutions
- Change the return type to a natively mappable one: void, int, long, boolean, double, float, Pointer, Structure, or String.
- Model C conventions directly: return int status codes, use Pointer for handles, and encode results through by-reference arguments (structures/pointers) instead of a complex return value.
- If a custom return type is required, attach a TypeMapper with a ToNativeConverter for that type via library options or Native.setTypeMapper.
Example fix
// before
public interface CmpCb extends Callback { Object invoke(Pointer a, Pointer b); }
// after
public interface CmpCb extends Callback { int invoke(Pointer a, Pointer b); } Defensive patterns
Strategy: validation
Validate before calling
static void checkReturnType(Method m) {
Class<?> r = m.getReturnType();
if (!(r == void.class || r.isPrimitive() || r == Pointer.class
|| Structure.class.isAssignableFrom(r) || r == String.class || r == WString.class)) {
throw new IllegalArgumentException("Unmappable callback return type: " + r);
}
} Type guard
static boolean isMappableNativeReturn(Class<?> r) {
return r == void.class || r.isPrimitive() || r == Pointer.class
|| Structure.class.isAssignableFrom(r) || r == String.class;
} Try / catch
try { registerCallback(cb); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith("Callback return type")) { /* change return type or add TypeMapper */ } throw e; } Prevention
- Return void or C-compatible primitives/Pointers from callbacks.
- Do not return boxed types or POJOs; encode results in by-reference arguments.
- Add a TypeMapper for custom return conversions.
- Smoke-test callback registration at startup.
When it happens
Trigger: Registering (first use of) a callback whose method returns e.g. Object, StringBuilder, Integer, List, or a custom class — the getNativeType(returnType) result fails isAllowableNativeType during CallbackReference construction.
Common situations: Writing callbacks like 'Object invoke(...)' expecting JNA to guess the C return; boxing return values (Boolean/Integer instead of boolean/int); returning application-specific result objects from a C callback.
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
- Callback argument <nativeParamTypes[i]> requires custom type
- Callback type must be an interface
- Method signature exceeds the maximum parameter count: <metho
- <type> is not derived from com.sun.jna.Callback
- Callback must implement a single public method, or one publi
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/f01cbef29dcc503c.
Report an issue: GitHub.