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

  1. Change the return type to a natively mappable one: void, int, long, boolean, double, float, Pointer, Structure, or String.
  2. 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.
  3. 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

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


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