quarkusio/quarkus · error · RuntimeException
has to be an interface
Error message
has to be an interface
What it means
The MongoPanacheRestProcessor validates at build time that each detected REST data resource is an interface. Passing a concrete class (annotated to be treated as a resource) throws RuntimeException '<class> has to be an interface'.
Source
Thrown at extensions/panache/mongodb-rest-data-panache/deployment/src/main/java/io/quarkus/mongodb/rest/data/panache/deployment/MongoPanacheRestProcessor.java:138
DataAccessImplementor dataAccessImplementor = new RepositoryDataAccessImplementor(repositoryClassName);
String resourceClass = resourceImplementor.implement(
classOutput, dataAccessImplementor, resourceInterface, entityType);
unremovableBeansProducer.produce(new UnremovableBeanBuildItem(
new UnremovableBeanBuildItem.BeanClassNameExclusion(repositoryClassName)));
restDataResourceProducer.produce(new RestDataResourceBuildItem(
new ResourceMetadata(resourceClass, resourceInterface, entityType, idType,
getEntityFields(index.getIndex(), entityType))));
if (capabilities.isPresent(Capability.RESTEASY)) {
bytecodeTransformersProducer.produce(
getEntityIdAnnotationTransformer(entityType, entityClassHelper.getIdField(entityType).name()));
}
}
}
private void validateResource(IndexView index, ClassInfo classInfo) {
if (!Modifier.isInterface(classInfo.flags())) {
throw new RuntimeException(classInfo.name() + " has to be an interface");
}
if (classInfo.interfaceNames().size() > 1) {
throw new RuntimeException(classInfo.name() + " should only extend REST Data Panache interface");
}
if (!index.getKnownDirectImplementors(classInfo.name()).isEmpty()) {
throw new RuntimeException(classInfo.name() + " should not be extended or implemented");
}
}
private List<Type> getGenericTypes(ClassInfo classInfo) {
return classInfo.interfaceTypes()
.stream()
.findFirst()
.orElseThrow(() -> new RuntimeException(classInfo.toString() + " does not have generic types"))
.asParameterizedType()
.arguments();View on GitHub (pinned to e1c734241f)
Solutions
- Convert the resource to an interface that extends the appropriate REST Data Panache interface (e.g. PanacheMongoRepositoryResource).
- Move the annotation from the entity class to a dedicated resource interface.
- Remove the annotation if a REST resource was not intended.
Example fix
// before
@PanacheMongoResource
public class BookResource { ... } // concrete class
// after
@PanacheMongoResource
public interface BookResource extends PanacheMongoRepositoryResource<Book, ObjectId> {}
Defensive patterns
Strategy: validation
Validate before calling
if (!resource.isInterface()) throw new IllegalArgumentException("@PanacheMongoResource target must be an interface: " + resource.getName()); Prevention
- Remember REST Data Panache resources are interfaces, not classes.
- Keep the entity class and the resource interface separate.
- Validate with a quick compile: 'interface X extends PanacheMongoRepositoryResource<E, ID>'.
When it happens
Trigger: Annotating a concrete class (not an interface) with the REST Data Panache resource annotation so the build-step processor picks it up in findEntityResources/findRepositoryResources.
Common situations: Misreading the REST Data Panache model: resources must be interfaces extending PanacheMongoEntityBase-style resource contracts, while the entity itself is a separate class.
Related errors
- should only extend REST Data Panache interface
- should not be extended or implemented
- Error while loading the liquibase changelogs: %s
- ${classInfo.name()} has to be an interface
- ${classInfo.name()} should only extend REST Data Panache int
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/ef851ae72bf147d3.
Report an issue: GitHub.