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
- Correct the declared return type in the Java mapping to match what the native side actually returns
- Validate the native return value type before mapping (add logging/debug in the native producer)
- 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
- Keep the Java return type in sync with what the native side actually produces
- Prefer declaring Object and narrowing with instanceof when the native return is dynamic
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
- Callback return type
- Callback type must be an interface
- library object passed to getNativeLibrary in not a proxy
- must be set from BOOL/BOOL[]
- must be set from byte[]
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)