quarkusio/quarkus · error · RuntimeException

Invalid proxy passed to recorder. ${rp} was created in a run

Error message

Invalid proxy passed to recorder. ${rp} 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.

What it means

Recorder objects returned by runtime-recorder methods are stored in the StartupContext and only exist when runtime init runs. A recorder executing in STATIC_INIT runs before that, so passing such a proxy into a static-init recorder would reference an object that does not exist yet. Quarkus detects this via the proxy's __static$$init flag and fails the build with this message.

Source

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

                    return value;
                }
            };
        } else if (param instanceof Enum) {
            Enum e = (Enum) param;
            return new DeferredParameter() {
                @Override
                ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                    ResultHandle nm = method.load(e.name());
                    return method.invokeStaticMethod(
                            ofMethod(e.getDeclaringClass(), "valueOf", e.getDeclaringClass(), String.class),
                            nm);
                }
            };
        } else if (param instanceof ReturnedProxy) {
            //if this is a proxy we just grab the value from the StartupContext
            ReturnedProxy rp = (ReturnedProxy) param;
            if (!rp.__static$$init() && staticInit) {
                throw new RuntimeException("Invalid proxy passed to recorder. " + rp
                        + " 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.");
            }
            String proxyId = rp.__returned$proxy$key();
            //because this is the result of a method invocation that may not have happened at param deserialization time
            //we just load it from the startup context
            return new DeferredParameter() {
                @Override
                ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                    return method.invokeVirtualMethod(ofMethod(StartupContext.class, "getValue", Object.class, String.class),
                            method.getMethodParam(0), method.load(proxyId));
                }
            };
        } else if (param instanceof Duration) {
            return new DeferredParameter() {
                @Override
                ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                    return method.invokeStaticMethod(ofMethod(Duration.class, "parse", Duration.class, CharSequence.class),
                            method.load(param.toString()));

View on GitHub (pinned to e1c734241f)

Solutions

  1. Change the consuming recorder to @Record(ExecutionTime.RUNTIME_INIT) so it runs when the proxy exists
  2. Obtain the value at STATIC_INIT time instead: call the producer recorder method in a STATIC_INIT @Record context
  3. Restructure so the static-init recorder only receives build-time-serializable values, and the runtime value is consumed in a runtime recorder
  4. Check the producer recorder's phase — a value you assume is static-init may come from RUNTIME_INIT
  5. If using RuntimeValue, ensure the underlying recorder method was recorded in the same phase as the consumer

Example fix

// before
@Record(ExecutionTime.STATIC_INIT)
void init(MyRecorder r, RuntimeValue<BeanContainer> bc) { ... } // bc from runtime recorder
// after
@Record(ExecutionTime.RUNTIME_INIT)
void init(MyRecorder r, RuntimeValue<BeanContainer> bc) { ... }
Defensive patterns

Strategy: type-guard

Validate before calling

// before passing a proxy into a static-init recorder
if (proxy instanceof io.quarkus.runtime.annotations.ReturnedProxy rp && !rp.__static$$init()) {
    throw new IllegalStateException("Runtime-init proxy cannot be consumed by a STATIC_INIT recorder");
}

Type guard

static boolean isStaticInitSafe(Object proxy) {
    return !(proxy instanceof io.quarkus.runtime.annotations.ReturnedProxy p) || p.__static$$init();
}

Prevention

When it happens

Trigger: In a @Recorder(Phase.STATIC_INIT) recorder method, a parameter is a proxy returned from another recorder that ran in Phase.RUNTIME_INIT (e.g. a RuntimeValue<BeanContainer> or proxy from a runtime-init record method).

Common situations: Extension developers wiring runtime-init results (CDI bean containers, HTTP handlers, clients created at runtime) into static-init recorders; copying recorder code between phases without adjusting the phase; upstream extension changing a recorder's phase.

Related errors


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