java-native-access/jna · error · ClassCastException

Return type does not match result

Error message

Return type <returnType> does not match result <resultClass>

What it means

When OBJECT_RETURN is allowed, JNA calls Native.invokeObject and then verifies the returned Java object is assignable to the declared return type. If the native code produced an object of an incompatible class, a ClassCastException is thrown describing both types.

Solutions

  1. Correct the declared return type in the Java mapping to match what the native side actually returns
  2. Validate the native return value type before mapping (add logging/debug in the native producer)
  3. If both types are plausible, declare the return as Object and downcast with instanceof checks

Example fix

// before
String getValue(); // native returns Integer
// after
Object getValue(); // then cast after instanceof check
Defensive patterns

Strategy: type-guard

Validate before calling

Object r = Native.invokeObject(f, peer, flags, args);
if (r != null && !expectedType.isAssignableFrom(r.getClass())) {
    throw new IllegalStateException("unexpected return " + r.getClass());
}

Type guard

static <T> T safeCast(Object r, Class<T> t) {
    return t.isInstance(r) ? t.cast(r) : null;
}

Try / catch

try {
    result = f.invoke(...);
} catch (ClassCastException e) {
    // declared return type does not match the object returned by native side
}

Prevention

When it happens

Trigger: Mapping a function with a Java return type T while allowing object returns, and the native callback/library returns an object whose class is not T or a subclass of T (e.g. declared Integer but native returned a String).

Common situations: Callback/Object-return APIs where the native side changed what it returns after a library upgrade; misdeclared return type in the Java interface.

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/0b47ac93eb126ebb. Report an issue: GitHub.

Appendix: source

Thrown at src/com/sun/jna/Function.java:489

            Pointer p = invokePointer(callFlags, args);
            if (p != null) {
                String[] arr = p.getWideStringArray(0);
                WString[] warr = new WString[arr.length];
                for (int i=0;i < arr.length;i++) {
                    warr[i] = new WString(arr[i]);
                }
                result = warr;
            }
        } else if (returnType==Pointer[].class) {
            Pointer p = invokePointer(callFlags, args);
            if (p != null) {
                result = p.getPointerArray(0);
            }
        } else if (allowObjects) {
            result = Native.invokeObject(this, this.peer, callFlags, args);
            if (result != null
                && !returnType.isAssignableFrom(result.getClass())) {
                throw new ClassCastException("Return type " + returnType
                                             + " does not match result "
                                             + result.getClass());
            }
        } else {
            throw new IllegalArgumentException("Unsupported return type " + returnType + " in function " + getName());
        }
        return result;
    }

    private Pointer invokePointer(int callFlags, Object[] args) {
        long ptr = Native.invokePointer(this, this.peer, callFlags, args);
        return ptr == 0 ? null : new Pointer(ptr);
    }

    private Object convertArgument(Object[] args, int index,
                                   Method invokingMethod, TypeMapper mapper,
                                   boolean allowObjects, Class<?> expectedType) {
        Object arg = args[index];

View on GitHub (pinned to d036ad9781)