quarkusio/quarkus · error · RuntimeException
You cannot invoke ${method.getName()}() directly on an objec
Error message
You cannot invoke ${method.getName()}() directly on an object returned from the bytecode recorder, you can only pass it back into the recorder as a parameter What it means
Objects returned from @Record method invocations are not real instances — they are proxies that record the invoked method calls into bytecode for later replay. Calling methods like hashCode/toString (other than the specially handled equals) directly on such a proxy cannot be recorded, so Quarkus throws. The proxy may only be passed back into the recorder as an argument of another recorded call.
Source
Thrown at core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java:1726
return staticInit;
}
if (method.getName().equals("toString")
&& method.getParameterCount() == 0
&& method.getReturnType().equals(String.class)) {
return "Runtime proxy of " + returnType + " with id " + key;
}
if (method.getName().equals("hashCode")
&& method.getParameterCount() == 0
&& method.getReturnType().equals(int.class)) {
return System.identityHashCode(proxy);
}
if (method.getName().equals("equals")
&& method.getParameterCount() == 1
&& method.getParameterTypes()[0] == Object.class
&& method.getReturnType().equals(boolean.class)) {
return proxy == args[0];
}
throw new RuntimeException(
"You cannot invoke " + method.getName()
+ "() directly on an object returned from the bytecode recorder, you can only pass it back into the recorder as a parameter");
}
}
interface BytecodeInstruction {
}
public interface ReturnedProxy {
String __returned$proxy$key();
boolean __static$$init();
}
static final class StoredMethodCall implements BytecodeInstruction {
final Class<?> theClass;
final Method method;View on GitHub (pinned to e1c734241f)
Solutions
- Do not call any methods on the returned proxy except passing it into another recorded recorder call
- Exclude the object from logging/debugging code (or use its class name, not the object)
- For tests, assert on recorded behavior at runtime rather than on the proxy object
Example fix
// before
System.out.println("got: " + recorder.getThing()); // calls toString
// after
// don't touch the proxy; only pass it on:
otherRecorder.use(recorder.getThing()); Defensive patterns
Strategy: try-catch
Type guard
static boolean isRecorderProxy(Object o) {
return o != null && Proxy.isProxyClass(o.getClass());
}
// only pass proxies back into recorder calls; never log/store them Try / catch
try {
sink.use(recorder.getThing()); // OK: passed back into recorder
} catch (RuntimeException e) {
if (String.valueOf(e.getMessage()).contains("You cannot invoke")) {
throw new IllegalStateException("Do not call methods on recorder-returned proxies", e);
}
throw e;
} Prevention
- Never log, println, or toString recorder return values
- Do not put recorder proxies into HashMaps/HashSets (hashCode is invoked)
- Keep recorder return values as opaque handles passed only to other recorded calls
When it happens
Trigger: Logging or debugging a value returned from a recorder-invoked method (accidentally invoking toString()/hashCode()); using the returned object in a Map/Set (which calls hashCode/equals); invoking a business method on it at build time expecting a real result.
Common situations: System.out.println of recorder return values during extension development; storing proxy objects in collections used at build time; assertion failures printing proxies in extension tests.
Related errors
- Public method ${methodInfo} cannot be proxied as it is final
- Invalid proxy passed to recorder. ${rp} was created in a run
- Unable to serialize ${param} as the wrong number of paramete
- Unable to determine the recordable constructor to use for ${
- Couldn't extract all parameters information for constructor
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/518d88376a8522c2.
Report an issue: GitHub.