{"record":{"id":"eb8d0eb7e4cd50fc","repo":"quarkusio/quarkus","slug":"has-to-be-an-interface","errorCode":null,"errorMessage":" has to be an interface","messagePattern":" has to be an interface","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/HibernateReactivePanacheRestProcessor.java","lineNumber":131,"sourceCode":"            String idType = generics.get(2).name().toString();\n\n            List<ClassInfo> listenersForEntityType = getListenersByEntityType(index, resourceMethodListeners, entityType);\n            DataAccessImplementor dataAccessImplementor = new RepositoryDataAccessImplementor(repositoryClassName);\n            String resourceClass = resourceImplementor.implement(\n                    classOutput, dataAccessImplementor, resourceInterface, entityType, listenersForEntityType);\n            // Make sure that repository bean is not removed and will be injected to the generated resource\n            unremovableBeansProducer.produce(new UnremovableBeanBuildItem(\n                    new UnremovableBeanBuildItem.BeanClassNameExclusion(repositoryClassName)));\n\n            restDataResourceProducer.produce(new RestDataResourceBuildItem(\n                    new ResourceMetadata(resourceClass, resourceInterface, entityType, idType,\n                            getEntityFields(index, entityType))));\n        }\n    }\n\n    private void validateResource(IndexView index, ClassInfo classInfo) {\n        if (!Modifier.isInterface(classInfo.flags())) {\n            throw new RuntimeException(classInfo.name() + \" has to be an interface\");\n        }\n\n        if (classInfo.interfaceNames().size() > 1) {\n            throw new RuntimeException(classInfo.name() + \" should only extend REST Data Panache interface\");\n        }\n\n        if (!index.getKnownDirectImplementors(classInfo.name()).isEmpty()) {\n            throw new RuntimeException(classInfo.name() + \" should not be extended or implemented\");\n        }\n    }\n\n    private List<Type> getGenericTypes(ClassInfo classInfo) {\n        return classInfo.interfaceTypes()\n                .stream()\n                .findFirst()\n                .orElseThrow(() -> new RuntimeException(classInfo.toString() + \" does not have generic types\"))\n                .asParameterizedType()\n                .arguments();","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/HibernateReactivePanacheRestProcessor.java#L113-L149","documentation":"REST Data Panache resources in Quarkus must be Java interfaces; the processor scans for annotated candidates and validates each. A concrete class annotated as a REST Data Panache resource cannot be used to generate data-backed endpoints, so validateResource throws.","triggerScenarios":"A class (not an interface) carries a REST Data Panache resource annotation, found via findEntityResources or findRepositoryResources during augmentation.","commonSituations":"Applying the resource annotation to a class instead of an interface; Kotlin 'class' vs 'interface' mistake; misunderstanding that REST Data Panache only generates implementations of interfaces.","solutions":["Convert the annotated type into an interface extending the appropriate REST Data Panache interface","Remove the annotation from the class and implement endpoints manually","Move the annotation to a new interface that targets the entity or repository"],"exampleFix":"// before\n@PanacheEntityResource\npublic class CustomerResource {}\n// after\n@PanacheEntityResource\npublic interface CustomerResource extends PanacheMongoResource<Customer> {}","handlingStrategy":"validation","validationCode":"if (!CustomerResource.class.isInterface()) throw new IllegalStateException(\"REST Data Panache resource must be an interface\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never put REST Data Panache annotations on classes","Kotlin: use 'interface', not 'class'","Check docs for the annotation's @Target"],"tags":["quarkus","rest-data","panache","interface"],"backgroundTag":"resource-must-be-interface","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}