{"record":{"id":"dad86ab3da3e0757","repo":"quarkusio/quarkus","slug":"failed-to-record-call-to-method-call-method","errorCode":null,"errorMessage":"Failed to record call to method ${call.method}","messagePattern":"Failed to record call to method (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java","lineNumber":493,"sourceCode":"                        ResultHandle createValue(MethodContext context, MethodCreator method, ResultHandle array) {\n                            return method.newInstance(ofConstructor(call.theClass));\n                        }\n                    };\n                    classInstanceVariables.put(call.theClass, value);\n                }\n                try {\n                    //for every parameter that was passed into the method we create a deferred value\n                    //this will allocate a space in the array, so the value can be deserialized correctly\n                    //even if the code for an invocation is split over several methods\n                    Class<?>[] parameterTypes = call.method.getParameterTypes();\n                    Annotation[][] parameterAnnotations = call.method.getParameterAnnotations();\n                    for (int i = 0; i < call.parameters.length; ++i) {\n                        call.deferredParameters[i] = loadObjectInstance(call.parameters[i], parameterMap,\n                                parameterTypes[i], Arrays.stream(parameterAnnotations[i])\n                                        .anyMatch(s -> s.annotationType() == RelaxedValidation.class));\n                    }\n                } catch (Exception e) {\n                    throw new RuntimeException(\"Failed to record call to method \" + call.method, e);\n                }\n            }\n        }\n        for (var e : existingRecorderValues.entrySet().stream()\n                .sorted(Comparator.comparing(re -> re.getKey().getName())).toList()) {\n            e.getValue().preWrite(parameterMap);\n        }\n\n        //when this is true it is no longer possible to allocate items in the array. this is a guard against programmer error\n        loadComplete = true;\n        //now we now know many items we have, create the array\n\n        MethodDescriptor createArrayDescriptor = ofMethod(mainMethod.getMethodDescriptor().getDeclaringClass(), CREATE_ARRAY,\n                \"[Ljava/lang/Object;\");\n        ResultHandle array = mainMethod.invokeVirtualMethod(createArrayDescriptor, mainMethod.getThis());\n\n        //this context manages the creation of new methods\n        //it tracks the number of instruction groups and when they hit a threshold it","sourceCodeStart":475,"sourceCodeEnd":511,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java#L475-L511","documentation":"During bytecode generation the recorder wraps any exception thrown while serializing a recorded method call's parameters into this RuntimeException, naming the recorded method. It is a wrapper: the real cause is the underlying serialization failure (unsupported type, substitution failure, oversized string, etc.). Inspect the 'Caused by' chain to find the actual problem.","triggerScenarios":"Any @Record* recorder method invocation whose argument cannot be serialized by BytecodeRecorderImpl.loadObjectInstance when writeBytecode() runs at build time; e.g. passing an unsupported object type, an object whose ObjectSubstitution.serialize() throws, or a String >65535 chars into a recorder method.","commonSituations":"Extension developers passing runtime objects (clients, services, streams) or large generated values into recorder methods; after upgrading Quarkus a type that was previously handled loses support; custom ObjectSubstitution implementations throwing during serialize().","solutions":["Read the 'Caused by' exception to identify which parameter failed to serialize","Ensure recorder method parameters are limited to types BytecodeRecorderImpl supports (primitives, String, enums, collections, maps, Optional, URL, Duration, Class, arrays, RuntimeValue proxies, or registered substitutions)","Register an ObjectSubstitution for the unsupported type via @Record with RecorderBytecodeTransformer/AnnotationProxy or the substitutions mechanism","If a String parameter exceeds 65535 chars, store it in a file/resource and pass the location instead","Check the parameter is not lazily throwing when serialized (e.g. a config value accessed at the wrong phase)"],"exampleFix":"// before: recorder receives an unsupported type\nrecorder.setClient(new SomeRuntimeClient());\n// after: pass serializable data (e.g. config values or primitives)\nrecorder.setClientConfig(host, port);","handlingStrategy":"try-catch","validationCode":"// before calling a recorder method in a build step\nstatic boolean isRecordable(Object p) {\n    return p == null || p instanceof String || p instanceof Number || p instanceof Boolean\n        || p instanceof Enum || p instanceof Class || p instanceof Optional\n        || p instanceof java.net.URL || p instanceof java.time.Duration\n        || p instanceof java.util.Collection || p instanceof java.util.Map\n        || p instanceof io.quarkus.runtime.RuntimeValue;\n}","typeGuard":"static boolean isRecordableType(Class<?> t) {\n    return t.isPrimitive() || String.class.isAssignableFrom(t) || Number.class.isAssignableFrom(t)\n        || Boolean.class.isAssignableFrom(t) || Enum.class.isAssignableFrom(t)\n        || Class.class.isAssignableFrom(t) || Collection.class.isAssignableFrom(t)\n        || Map.class.isAssignableFrom(t) || Optional.class.isAssignableFrom(t);\n}","tryCatchPattern":"try {\n    recorder.someMethod(param);\n} catch (RuntimeException e) {\n    if (e.getCause() != null) {\n        throw new IllegalStateException(\"Recorder parameter not serializable: \" + param.getClass(), e.getCause());\n    }\n    throw e;\n}","preventionTips":["Pass only primitives, Strings, enums, collections, maps, Optional, Class and RuntimeValue proxies through recorders","Register an ObjectSubstitution for any custom type that must cross the recorder boundary","Read the full 'Caused by' chain — this error is always a wrapper","Keep recorded payloads small; move big data to build-time-generated resources"],"tags":["quarkus","build-time","recorder","serialization"],"backgroundTag":"build-time-recording-failed","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}