quarkusio/quarkus · error · RuntimeException

You can only annotate one class with @UserDefinition

Error message

You can only annotate one class with @UserDefinition

What it means

The security-jpa build step only supports a single @UserDefinition-annotated class per application: it generates one identity provider from that entity. If the Jandex index contains more than one @UserDefinition class, provideJpaSecurityDefinition throws at build time.

Source

Thrown at extensions/security-jpa-common/deployment/src/main/java/io/quarkus/security/jpa/common/deployment/QuarkusSecurityJpaCommonProcessor.java:34

import io.quarkus.security.jpa.Roles;
import io.quarkus.security.jpa.UserDefinition;
import io.quarkus.security.jpa.Username;

class QuarkusSecurityJpaCommonProcessor {

    private static final DotName DOTNAME_USER_DEFINITION = DotName.createSimple(UserDefinition.class.getName());
    private static final DotName DOTNAME_USERNAME = DotName.createSimple(Username.class.getName());
    private static final DotName DOTNAME_ROLES = DotName.createSimple(Roles.class.getName());
    static final DotName DOTNAME_PASSWORD = DotName.createSimple(Password.class.getName());

    @BuildStep
    void provideJpaSecurityDefinition(ApplicationIndexBuildItem index, PanacheEntityPredicateBuildItem panacheEntityPredicate,
            BuildProducer<JpaSecurityDefinitionBuildItem> producer) {

        // Generate an IdentityProvider if we have a @UserDefinition
        List<AnnotationInstance> userDefinitions = index.getIndex().getAnnotations(DOTNAME_USER_DEFINITION);
        if (userDefinitions.size() > 1) {
            throw new RuntimeException("You can only annotate one class with @UserDefinition");
        } else if (!userDefinitions.isEmpty()) {
            ClassInfo userDefinitionClass = userDefinitions.get(0).target().asClass();
            AnnotationTarget annotatedUsername = getSingleAnnotatedElement(index.getIndex(), DOTNAME_USERNAME);
            AnnotationTarget annotatedPassword = getSingleAnnotatedElement(index.getIndex(), DOTNAME_PASSWORD);
            AnnotationTarget annotatedRoles = getSingleAnnotatedElement(index.getIndex(), DOTNAME_ROLES);
            // collect associated getters if required
            JpaSecurityDefinition jpaSecurityDefinition = new JpaSecurityDefinition(index.getIndex(),
                    userDefinitionClass,
                    panacheEntityPredicate.isPanache(userDefinitionClass),
                    annotatedUsername,
                    annotatedPassword,
                    annotatedRoles);
            producer.produce(new JpaSecurityDefinitionBuildItem(jpaSecurityDefinition));
        }
    }

}

View on GitHub (pinned to e1c734241f)

Solutions

  1. Keep exactly one @UserDefinition class; remove @UserDefinition from the others (plain @Entity is fine).
  2. Merge the two user entities into one with a role/type discriminator if both represent users.
  3. Move the second user definition into a separate library/module not on the application index, or delete dead entities.

Example fix

// before
@UserDefinition @Entity public class User { ... }
@UserDefinition @Entity public class Admin { ... }

// after
@UserDefinition @Entity public class User { ... }
@Entity public class Admin { ... }
Defensive patterns

Strategy: validation

Validate before calling

long n = allEntities.stream()
    .filter(c -> c.isAnnotationPresent(UserDefinition.class))
    .count();
if (n > 1) throw new IllegalStateException("Only one @UserDefinition class is allowed");

Prevention

When it happens

Trigger: Annotating two or more entity classes with @io.quarkus.security.jpa.UserDefinition and building the application.

Common situations: Adding a second user entity for a new user type without realizing only one is supported; copying an example entity into a test/multi-module app where both end up in the application index; keeping an old @UserDefinition class after introducing a new one.

Related errors


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