oracle/graal · error · IllegalArgumentException
methods with same signature {} but incompatible return types
Error message
methods with same signature {} but incompatible return types: {} and others What it means
Thrown by EspressoForeignProxyGenerator's return-type coverage check: when two proxied interfaces declare the same method signature but their return types are incompatible, the first failure mode triggers if the newly seen return type is primitive — a primitive can never be 'covered' by a reference return type, so the proxy cannot implement both methods and creation aborts. Message includes the friendly signature and the offending primitive type.
Source
Thrown at espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/EspressoForeignProxyGenerator.java:731
private static void checkReturnTypes(List<ProxyMethod> methods) {
/*
* If there is only one method with a given signature, there cannot be a conflict. This is
* the only case in which a primitive (or void) return type is allowed.
*/
if (methods.size() < 2) {
return;
}
/*
* List of return types that are not yet known to be assignable from ("covered" by) any of
* the others.
*/
LinkedList<Klass> uncoveredReturnTypes = new LinkedList<>();
nextNewReturnType: for (ProxyMethod pm : methods) {
Klass newReturnType = pm.returnType.getRawType();
if (newReturnType.isPrimitive()) {
throw new IllegalArgumentException(
"methods with same signature " +
getFriendlyMethodSignature(pm.methodName,
pm.parameterTypes) +
" but incompatible return types: " +
newReturnType.getName() + " and others");
}
boolean added = false;
/*
* Compare the new return type to the existing uncovered return types.
*/
ListIterator<Klass> liter = uncoveredReturnTypes.listIterator();
while (liter.hasNext()) {
Klass uncoveredReturnType = liter.next();
/*
* If an existing uncovered return type is assignable to this new one, then we can
* forget the new one.View on GitHub (pinned to a66e9ccd1d)
Solutions
- Do not proxy those two interfaces together — pick one, or wrap one behind an adapter object.
- Change one interface's method return type so they are assignable (e.g. both reference types with a common subtype).
- If you control the interfaces, rename the colliding method on one of them.
Example fix
// before
interface A { int fetch(); }
interface B { Object fetch(); }
proxy(A.class, B.class); // throws
// after
interface B { Object fetchValue(); } // renamed, no clash
proxy(A.class, B.class); Defensive patterns
Strategy: validation
Validate before calling
// reject proxies over same-signature methods with primitive vs reference returns
Map<String, Klass> returnsBySignature = new HashMap<>();
for (Method m : allMethods(interfaces)) {
String sig = m.getName() + Arrays.toString(m.getParameterTypes());
Klass prev = returnsBySignature.putIfAbsent(sig, m.getReturnType());
if (prev != null && !prev.isAssignableTo(m.getReturnType()) && !m.getReturnType().isAssignableTo(prev)) {
throw new IllegalArgumentException("incompatible returns for " + sig);
}
} Try / catch
try {
generator.getProxy(context, loader, interfaces);
} catch (IllegalArgumentException e) {
// message contains the conflicting signature: split the proxy or fix the interfaces
} Prevention
- Do not combine interfaces with same-name, same-parameter methods of incompatible return types.
- Watch for primitive vs boxed return drift across library versions.
- Prefer adapters over mega-proxies when merging third-party SPIs.
When it happens
Trigger: Proxying interfaces where one declares 'int m()' and another declares 'Object m()' (same name and parameter types): the primitive return type hits the isPrimitive() branch and throws. Replicates java.lang.reflect.Proxy's 'methods with same signature but incompatible return types' error.
Common situations: Cobbling together proxies over unrelated third-party interfaces that happen to share a method name; version drift where one interface's method signature changed its return type; bridge-style APIs mixing boxed and primitive returns.
Related errors
- methods with same signature {} but incompatible return types
- cannot have non-public interfaces in different packages
- non-public interface is not defined by the given loader
- ${targetModule} can't access ${interfaceName}
- Invalid guest type
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/3323471f4bd9fef1.
Report an issue: GitHub.