quarkusio/quarkus · error · RuntimeException

should only extend REST Data Panache interface

Error message

${classInfo.name()} should only extend REST Data Panache interface

What it means

validateResource enforces that a REST Data Panache resource interface extends exactly one interface. Extending more than one interface breaks the generic signature extraction, so the build fails with this RuntimeException.

Solutions

  1. Remove all but the single REST Data Panache interface from the extends clause
  2. Move shared methods to the entity or a separate service, not the resource interface
  3. Split into multiple resource interfaces if two domains are needed

Example fix

// before
public interface PersonResource extends PanacheEntityResource<Person, Long>, Serializable {}
// after
public interface PersonResource extends PanacheEntityResource<Person, Long> {}
Defensive patterns

Strategy: validation

Validate before calling

if (resourceClass.getInterfaces().length != 1)
    throw new IllegalStateException(resourceClass + " must extend exactly one Panache REST Data interface");

Prevention

When it happens

Trigger: A resource interface extending two or more interfaces, e.g. 'interface PersonResource extends PanacheEntityResource<Person, Long>, Serializable' or extending two Panache resource interfaces.

Common situations: Adding Serializable/Comparable to a resource interface; composing several resource interfaces into one.

Related errors


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

Appendix: source

Thrown at extensions/panache/hibernate-orm-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/HibernateOrmPanacheRestProcessor.java:153

            String resourceClass = resourceImplementor.implement(
                    classOutput, dataAccessImplementor, resourceInterface, entityType, listenersForEntityType);
            // Make sure that repository bean is not removed and will be injected to the generated resource
            unremovableBeansProducer.produce(new UnremovableBeanBuildItem(
                    new UnremovableBeanBuildItem.BeanClassNameExclusion(repositoryClassName)));

            restDataResourceProducer.produce(new RestDataResourceBuildItem(
                    new ResourceMetadata(resourceClass, resourceInterface, entityType, idType,
                            getEntityFields(index.getIndex(), entityType))));
        }
    }

    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)