quarkusio/quarkus · error · RuntimeException

You can only annotate one field or method with @${annotation

Error message

You can only annotate one field or method with @${annotation}

What it means

The JPA security extension expects exactly one element in the application indexed by Jandex to carry a given annotation (such as @Username, @Password, or @Roles). If more than one field or method carries that annotation, the build-time generator cannot decide which one to use and aborts the build.

Source

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

            trueBranch.returnNull();
        });
        // Builder builder = JpaIdentityProviderUtil.trusted(request);
        Expr builder = bc.invokeStatic(MethodDesc.of(JpaIdentityProviderUtil.class,
                "trusted",
                QuarkusSecurityIdentity.Builder.class,
                TrustedAuthenticationRequest.class),
                requestParam);
        LocalVar builderVar = bc.localVar("builder", QuarkusSecurityIdentity.Builder.class, builder);

        setupRoles(index, jpaSecurityDefinition, panacheEntityPredicate, userVar, builderVar, bc);
    }

    static AnnotationTarget getSingleAnnotatedElement(Index index, DotName annotation) {
        List<AnnotationInstance> annotations = index.getAnnotations(annotation);
        if (annotations.isEmpty()) {
            return null;
        } else if (annotations.size() > 1) {
            throw new RuntimeException("You can only annotate one field or method with @" + annotation);
        }
        return annotations.get(0).target();
    }

    private static void setupRoles(Index index, JpaSecurityDefinition jpaSecurityDefinition,
            PanacheEntityPredicateBuildItem panacheEntityPredicate, Expr userVar,
            LocalVar builderVar, BlockCreator bc) {
        Expr role = jpaSecurityDefinition.roles.readValue(bc, userVar);
        // role: user.getRole()
        boolean handledRole = false;
        Type rolesType = jpaSecurityDefinition.roles.type();
        switch (rolesType.kind()) {
            case ARRAY:
                // FIXME: support non-JPA-backed array roles?
                break;
            case CLASS:
                if (rolesType.name().equals(DotNames.STRING)) {
                    // JpaIdentityProviderUtil.addRoles(builder, :role)

View on GitHub (pinned to e1c734241f)

Solutions

  1. Keep the annotation on exactly one field or method in the whole application; remove duplicate @Username/@Password/@Roles annotations.
  2. If you need multiple user representations, annotate only the @UserDefinition entity and remove annotations from other classes.
  3. Move duplicate annotations into plain fields (no security annotations) if they are used for non-authentication purposes.

Example fix

// before: two annotated classes
@UserDefinition public class User { @Roles public String role; }
public class AdminUser { @Roles public String role; }

// after
@UserDefinition public class User { @Roles public String role; }
public class AdminUser { public String role; }
Defensive patterns

Strategy: validation

Validate before calling

// before build: ensure single occurrence of each security annotation
long count = Stream.of(entityClasses)
    .flatMap(c -> Arrays.stream(c.getDeclaredFields()))
    .filter(f -> f.isAnnotationPresent(Username.class))
    .count();
if (count > 1) throw new IllegalStateException("@Username must appear on exactly one member");

Prevention

When it happens

Trigger: Declaring @Username, @Password, or @Roles on more than one field or getter — across all classes in the application index, not just within one entity — then building the application with a @UserDefinition entity present.

Common situations: Having a @UserDefinition entity plus another class (e.g. an admin entity or DTO) also annotated with @Roles or @Username; leftover annotations after refactoring; multiple user entity candidates kept around 'temporarily'.

Related errors


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