{"record":{"id":"518d88376a8522c2","repo":"quarkusio/quarkus","slug":"you-cannot-invoke-method-getname-directly-o","errorCode":null,"errorMessage":"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","messagePattern":"You cannot invoke (.+?)\\(\\) directly on an object returned from the bytecode recorder, you can only pass it back into the recorder as a parameter","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java","lineNumber":1726,"sourceCode":"                return staticInit;\n            }\n            if (method.getName().equals(\"toString\")\n                    && method.getParameterCount() == 0\n                    && method.getReturnType().equals(String.class)) {\n                return \"Runtime proxy of \" + returnType + \" with id \" + key;\n            }\n            if (method.getName().equals(\"hashCode\")\n                    && method.getParameterCount() == 0\n                    && method.getReturnType().equals(int.class)) {\n                return System.identityHashCode(proxy);\n            }\n            if (method.getName().equals(\"equals\")\n                    && method.getParameterCount() == 1\n                    && method.getParameterTypes()[0] == Object.class\n                    && method.getReturnType().equals(boolean.class)) {\n                return proxy == args[0];\n            }\n            throw new RuntimeException(\n                    \"You cannot invoke \" + method.getName()\n                            + \"() directly on an object returned from the bytecode recorder, you can only pass it back into the recorder as a parameter\");\n        }\n    }\n\n    interface BytecodeInstruction {\n\n    }\n\n    public interface ReturnedProxy {\n        String __returned$proxy$key();\n\n        boolean __static$$init();\n    }\n\n    static final class StoredMethodCall implements BytecodeInstruction {\n        final Class<?> theClass;\n        final Method method;","sourceCodeStart":1708,"sourceCodeEnd":1744,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java#L1708-L1744","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nSystem.out.println(\"got: \" + recorder.getThing()); // calls toString\n// after\n// don't touch the proxy; only pass it on:\notherRecorder.use(recorder.getThing());","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"static boolean isRecorderProxy(Object o) {\n    return o != null && Proxy.isProxyClass(o.getClass());\n}\n// only pass proxies back into recorder calls; never log/store them","tryCatchPattern":"try {\n    sink.use(recorder.getThing()); // OK: passed back into recorder\n} catch (RuntimeException e) {\n    if (String.valueOf(e.getMessage()).contains(\"You cannot invoke\")) {\n        throw new IllegalStateException(\"Do not call methods on recorder-returned proxies\", e);\n    }\n    throw e;\n}","preventionTips":["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"],"tags":["quarkus","bytecode-recording","proxy"],"backgroundTag":"build-time-proxy-misuse","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}