java-native-access/jna · error · IllegalArgumentException
Callback argument <nativeParamTypes[i]> requires custom type
Error message
Callback argument <nativeParamTypes[i]> requires custom type conversion
What it means
IllegalArgumentException thrown while registering a native callback when a callback METHOD PARAMETER type does not map to an allowable native type (see isAllowableNativeType: boolean, byte, char, short, int, long, float, double, Pointer, Structure, String/WString/Buffer-backed types, and by-reference wrappers). JNA cannot marshal an arbitrary Java object (e.g. java.lang.StringBuilder, boxed types, custom classes) into a native callback argument without a TypeMapper/custom conversion, so registration fails immediately.
Source
Thrown at src/com/sun/jna/CallbackReference.java:314
// to match the true Java callback method signature
if (mapper != null) {
for (int i=0;i < nativeParamTypes.length;i++) {
FromNativeConverter rc = mapper.getFromNativeConverter(nativeParamTypes[i]);
if (rc != null) {
nativeParamTypes[i] = rc.nativeType();
}
}
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) {View on GitHub (pinned to d036ad9781)
Solutions
- Change the callback parameter to a natively mappable type: primitive (int, double, ...), Pointer, Structure, String, or CallbackReference-supported by-reference types.
- If you must receive a custom type, register a TypeMapper (e.g. via Library.OPTION_TYPE_MAPPER or Native.setTypeMapper) that provides ToNativeConverter/FromNativeConverter for that class.
- For pointer-sized values use Pointer or long/PointerType instead of boxed Number subclasses; for C strings use String/WString or a byte[]/char[] buffer parameter.
Example fix
// before
public interface ProgressCb extends Callback { void invoke(StringBuilder msg); }
// after
public interface ProgressCb extends Callback { void invoke(Pointer msg); }
// or keep String:
public interface ProgressCb extends Callback { void invoke(String msg); } Defensive patterns
Strategy: validation
Validate before calling
static void checkParamTypes(Method m) {
for (Class<?> p : m.getParameterTypes()) {
if (!(p.isPrimitive() || p == Pointer.class || Structure.class.isAssignableFrom(p)
|| p == String.class || p == WString.class || p == byte[].class || p == char[].class
|| Callback.class.isAssignableFrom(p))) {
throw new IllegalArgumentException("Unmappable callback arg type: " + p);
}
}
} Type guard
static boolean isMappableNativeParam(Class<?> p) {
return p.isPrimitive() || p == Pointer.class || Structure.class.isAssignableFrom(p)
|| p == String.class || p == WString.class;
} Try / catch
try { registerCallback(cb); } catch (IllegalArgumentException e) { if (e.getMessage().contains("requires custom type conversion")) { /* fix signature or add TypeMapper */ } throw e; } Prevention
- Model C types exactly: primitives, Pointer, Structure, String.
- Never use boxed or collection types in callback signatures.
- Register a TypeMapper up front when custom types are needed.
- Write a unit test that instantiates each callback early.
When it happens
Trigger: Creating a callback whose interface method declares a parameter of a type outside the allowable native set — e.g. void callback(StringBuilder sb), void callback(Integer i), or a custom POJO — when the callback is registered with the native runtime (Native.createNativeCallback path, first use in Native.loadLibrary'd function or Structure field).
Common situations: Copying Java signatures (java.util.List, StringBuilder, boxed Integer/Double) into a callback meant to receive C arguments; forgetting a TypeMapper on the library options for custom types; typos like using 'Integer' instead of 'int'.
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 return type <returnType> requires custom type conve
- 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/93162aced831a483.
Report an issue: GitHub.