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
- Keep exactly one @UserDefinition class; remove @UserDefinition from the others (plain @Entity is fine).
- Merge the two user entities into one with a role/type discriminator if both represent users.
- 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
- Maintain a single @UserDefinition entity per application.
- Grep for @UserDefinition before adding a new user entity.
- Merge user variants into one entity with a discriminator.
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
- You can only annotate one field or method with @${annotation
- Method %s#%s should not have been added as an additional sec
- Class %s is annotated with multiple security annotations %s
- Method %s of class %s is annotated with multiple security an
- Unknown password type: ${passwordType}
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/d4e8be34e212fd4c.
Report an issue: GitHub.