quarkusio/quarkus · error · RuntimeException

Cannot use ${method} as a recorder method as the return type

Error message

Cannot use ${method} as a recorder method as the return type cannot be proxied. Use RuntimeValue to wrap the return value instead.

What it means

Recorder methods' return values must be either void, primitively recordable, or proxyable types that Quarkus can substitute with recorded proxies. If a recorder method returns a non-proxiable type (e.g. final class, primitive-wrapper misuse, unrecordable class), invoke() cannot represent the result, so it fails with guidance to wrap the value in RuntimeValue instead.

Source

Thrown at core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java:353

                                throw new RuntimeException("Invalid proxy passed to recorder. Parameter " + i + " of type "
                                        + method.getParameterTypes()[i]
                                        + " was created in a runtime recorder method, while this recorder is for a static init method. The object will not have been created at the time this method is run.");
                            }
                        }
                    }
                }
                StoredMethodCall storedMethodCall = new StoredMethodCall(theClass, method, args);
                storedMethodCalls.add(storedMethodCall);
                Class<?> returnType = method.getReturnType();
                if (method.getName().equals("toString")
                        && method.getParameterCount() == 0
                        && returnType.equals(String.class)) {
                    return proxy.getClass().getName();
                }

                boolean voidMethod = method.getReturnType().equals(void.class);
                if (!voidMethod && !isProxiable(method.getReturnType())) {
                    throw new RuntimeException("Cannot use " + method
                            + " as a recorder method as the return type cannot be proxied. Use RuntimeValue to wrap the return value instead.");
                }
                if (voidMethod) {
                    return null;
                }
                ProxyInstance instance = getProxyInstance(returnType);
                if (instance == null) {
                    return null;
                }

                storedMethodCall.returnedProxy = instance.proxy;
                storedMethodCall.proxyId = instance.key;
                return instance.proxy;
            }

        };

        try {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Change the recorder method return type to RuntimeValue<T> and construct with new RuntimeValue<>(instance)
  2. Return an interface or non-final class that Quarkus can proxy
  3. Return a primitive/String/List/Map directly if the data is recordable
  4. Split the method: return recordable data, and do non-recordable work inside the recorder method itself

Example fix

// before
@Recorder
public MyFinalService service() { return new MyFinalService(); }
// after
@Recorder
public RuntimeValue<MyFinalService> service() { return new RuntimeValue<>(new MyFinalService()); }
Defensive patterns

Strategy: type-guard

Validate before calling

static boolean recorderReturnOk(Class<?> t) {
    return t.isPrimitive() || t == void.class || t == String.class || !Modifier.isFinal(t.getModifiers());
}

Type guard

static boolean recorderReturnOk(Class<?> t) {
    return t.isPrimitive() || t == void.class || t == String.class || !Modifier.isFinal(t.getModifiers());
}

Prevention

When it happens

Trigger: Declaring a @Recorder method whose return type fails isProxiable(): final classes, classes without usable constructors, or other non-recordable types returned directly instead of RuntimeValue<T>.

Common situations: Returning configuration POJOs/records/final builder classes from recorders; returning Optional or streams; returning third-party final classes from recorder APIs.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/cf6d5899bc16f82d. Report an issue: GitHub.