quarkusio/quarkus · error · IllegalStateException
@CachedResults class must be an interface or declare a no-ar
Error message
@CachedResults class must be an interface or declare a no-args constructor:
What it means
The class injected with @CachedResults must either be an interface (so the extension can generate a synthetic caching implementation) or a concrete class with a public no-args constructor. Any other shape cannot be proxied/generated and the build fails.
Source
Thrown at extensions/cache/deployment/src/main/java/io/quarkus/cache/deployment/CachedResultsProcessor.java:356
if (annotation.target().kind() == Kind.FIELD) {
type = annotation.target().asField().type();
} else if (annotation.target().kind() == Kind.METHOD_PARAMETER) {
type = annotation.target().asMethodParameter().type();
} else {
throw new IllegalStateException("Unsupported target:" + annotation.target());
}
if (type.kind() != Type.Kind.CLASS) {
throw new IllegalStateException("Invalid type: " + type);
}
ClassInfo injectedClazz = index.getClassByName(type.name());
if (injectedClazz == null) {
throw new IllegalStateException("Injected class not found in index: " + type.name());
}
if (!injectedClazz.isInterface()
&& !injectedClazz.hasNoArgsConstructor()) {
throw new IllegalStateException(
"@CachedResults class must be an interface or declare a no-args constructor: " + injectedClazz);
}
return new CachedResultsInjectConfig(cacheName, lockTimeout, keyGenerator, injectedClazz,
// consider all but @CachedResults and @Inject
annotation.target().declaredAnnotations().stream().filter(
a -> !a.name().equals(CACHED_RESULTS)
&& !a.name().equals(INJECT))
.toList(),
exclude);
}
record CachedResultsInjectConfig(String cacheName, Long lockTimeout, DotName keyGenerator, ClassInfo injectedClazz,
Collection<AnnotationInstance> annotations, String exclude) {
}
record MethodKey(String name, List<TypeEquivalenceKey> params, TypeEquivalenceKey returnType) {
View on GitHub (pinned to e1c734241f)
Solutions
- Make the injected type an interface and inject that.
- Add a public no-arg constructor to the concrete class and supply dependencies another way (setters/field injection).
- Move @CachedResults to a generated/accessor interface instead of caching the concrete class directly.
Example fix
// before
@ApplicationScoped
public class PriceService {
public PriceService(Config c) { ... }
}
// after
public interface PriceService { Price get(String id); }
@Inject @CachedResults(cacheName = "prices")
PriceService priceService; // interface target Defensive patterns
Strategy: validation
Validate before calling
Class<?> c = com.example.PriceService.class;
if (!c.isInterface() && java.lang.reflect.Modifier.isAbstract(c.getModifiers())) {
throw new IllegalStateException("@CachedResults type must be an interface or concrete with no-arg ctor");
}
if (!c.isInterface() && c.getDeclaredConstructors().length > 0
&& java.util.Arrays.stream(c.getConstructors()).noneMatch(k -> k.getParameterCount() == 0)) {
throw new IllegalStateException("@CachedResults concrete class needs a public no-arg constructor");
} Type guard
static boolean isValidCachedResultsType(Class<?> c) {
return c.isInterface() || java.util.Arrays.stream(c.getConstructors())
.anyMatch(k -> k.getParameterCount() == 0);
} Prevention
- Design cached types as interfaces
- If concrete, always provide a public no-arg constructor
- Resolve dependencies via CDI injection fields, not constructors, on such classes
When it happens
Trigger: Annotating an injected concrete class that only has constructors taking arguments (no default constructor), or an abstract class without a no-arg constructor.
Common situations: Injecting a pre-existing service class with mandatory constructor dependencies and expecting @CachedResults to wrap it; migrating code from interface-based design to concrete classes.
Related errors
- Multiple @Inject constructors on ${theClass}
- Unsupported target:
- Invalid type:
- Injected class not found in index:
- Cache key generator instantiation failed
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/6abb825c3874f2de.
Report an issue: GitHub.