quarkusio/quarkus · error · RuntimeException
Cannot inject object of type ${param}
Error message
Cannot inject object of type ${param} What it means
BytecodeRecorderImpl can satisfy recorder constructor parameters that are Class or simple known types only if an object of that exact type was previously loaded/recorded in the same recorder context (findLoaded). When a constructor parameter of raw type Class has no corresponding recorded instance, it throws this RuntimeException at augmentation time.
Source
Thrown at core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java:1818
void preWrite(Map<Object, DeferredParameter> parameterMap) {
if (injectCtor != null) {
try {
java.lang.reflect.Type[] parameterTypes = injectCtor.getGenericParameterTypes();
Annotation[][] parameterAnnotations = injectCtor.getParameterAnnotations();
for (int i = 0; i < parameterTypes.length; i++) {
java.lang.reflect.Type param = parameterTypes[i];
var constantHolder = findConstantForParam(param);
if (constantHolder != null) {
deferredParameters.add(loadObjectInstance(constantHolder.value, parameterMap,
constantHolder.type, Arrays.stream(parameterAnnotations[i])
.anyMatch(s -> s.annotationType() == RelaxedValidation.class)));
continue;
}
if (param instanceof Class<?>) {
var result = findLoaded(null, (Class<?>) param);
if (result == null) {
throw new RuntimeException("Cannot inject object of type " + param);
}
deferredParameters.add(result);
} else if (param instanceof ParameterizedType paramType
&& paramType.getRawType() == RuntimeValue.class) {
if (staticInit) {
deferredParameters.add(new DeferredParameter() {
@Override
ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
return method.newInstance(MethodDescriptor.ofConstructor(RuntimeValue.class));
}
});
} else {
var result = findLoaded(null, (Class<?>) paramType.getActualTypeArguments()[0]);
if (result == null) {
throw new RuntimeException("Cannot inject object of type " + param);
}
deferredParameters.add(new DeferredParameter() {
@OverrideView on GitHub (pinned to e1c734241f)
Solutions
- Remove the Class-typed parameter and pass the value explicitly through a recorded method call instead
- Record/register the required object in the recorder context before the class is instantiated
- Change the constructor to accept only types the recorder can handle (primitives, String, Class with a recorded value, known config types)
- Store the class name as a String and resolve it at runtime
Example fix
// before
@Inject
MyRecorderConfig(Class<?> type) { this.type = type; }
// after
@Inject
MyRecorderConfig(String typeName) { this.typeName = typeName; } // resolve Class.forName at runtime Defensive patterns
Strategy: validation
Validate before calling
static boolean ctorOnlyInjectableRawClassParams(Class<?> c) {
return java.util.Arrays.stream(c.getDeclaredConstructors())
.filter(k -> java.util.Arrays.stream(k.getAnnotations())
.anyMatch(a -> a.annotationType().getSimpleName().equals("Inject")))
.allMatch(k -> java.util.Arrays.stream(k.getParameterTypes())
.noneMatch(p -> p == Class.class));
} Try / catch
try {
recorderMethod.invoke(...);
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Cannot inject object of type")) {
throw new IllegalStateException("Register the value in the recorder before instantiation", e);
}
throw e;
} Prevention
- Avoid Class-typed constructor parameters in recorded classes
- Pass class names as String and resolve with Class.forName at runtime
- Record/register every object a constructor needs before instantiation in the same recorder
When it happens
Trigger: An @Inject-annotated constructor of a recorded class declares a parameter typed as Class<?> (or another injectable raw type) and no value of that type has been recorded into the BytecodeRecorder before the object is created.
Common situations: Extension authors add a Class-typed parameter to a recorded object's constructor expecting it to be auto-wired; refactoring a recorder support class without registering the parameter value via recorder methods (e.g. recorder.registerParameters / returned recorded objects).
Related errors
- Could not determine constructor for ${theClass} add @Inject
- Failed to prepare injector constructor ${injectCtor} of byte
- Unsupported value: ${value}
- Cannot create new DeferredArrayStoreParameter after array ha
- Failed to injector constructor ${injectCtor} of bytecode rec
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/3f4997efbed2a396.
Report an issue: GitHub.