quarkusio/quarkus · error · DeploymentException

Method '' of class '' contains multiple HTTP method annotati

Error message

Method '' of class '' contains multiple HTTP method annotations.

What it means

EndpointIndexer.validateHttpAnnotations checks that a JAX-RS resource method carries at most one HTTP method annotation (@GET, @POST, @PUT, etc.). If two recognized HTTP method annotations are present on the same method, createEndpoints fails with a DeploymentException naming the method and class. A resource method must map to exactly one HTTP verb.

Source

Thrown at independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java:540

     * By default, we are not removing the trailing slash.
     */
    protected String handleTrailingSlash(String path) {
        return path;
    }

    private void validateHttpAnnotations(MethodInfo info) {
        List<AnnotationInstance> annotationInstances = info.annotations();
        Set<DotName> allMethodAnnotations = new HashSet<>(annotationInstances.size());
        for (AnnotationInstance instance : annotationInstances) {
            allMethodAnnotations.add(instance.name());
        }
        int httpAnnotationCount = 0;
        for (DotName dotName : allMethodAnnotations) {
            if (httpAnnotationToMethod.containsKey(dotName)) {
                httpAnnotationCount++;
            }
            if (httpAnnotationCount > 1) {
                throw new DeploymentException("Method '" + info.name() + "' of class '" + info.declaringClass().name()
                        + "' contains multiple HTTP method annotations.");
            }
        }
    }

    private static boolean hasProperModifiers(MethodInfo info) {
        if (isSynthetic(info.flags())) {
            log.debug("Method '" + info.name() + " of Resource class '" + info.declaringClass().name()
                    + "' is a synthetic method and will therefore be ignored");
            return false;
        }
        if ((info.flags() & Modifier.PUBLIC) == 0) {
            log.warn("Method '" + info.name() + " of Resource class '" + info.declaringClass().name()
                    + "' is not public and will therefore be ignored");
            return false;
        }
        if ((info.flags() & Modifier.STATIC) != 0) {
            log.warn("Method '" + info.name() + " of Resource class '" + info.declaringClass().name()

View on GitHub (pinned to e1c734241f)

Solutions

  1. Remove one of the HTTP method annotations so the method handles a single verb
  2. Split the logic into two methods, one per HTTP verb
  3. If multiple verbs should be handled, implement @OPTIONS/@HttpMethod overloads as separate methods or use a custom annotation only for verbs not built in

Example fix

// before
@Path("/item")
@GET
@POST
public Item getOrCreate() { ... }
// after
@GET public Item get() { ... }
@POST public Item create() { ... }
Defensive patterns

Strategy: validation

Validate before calling

long httpAnnotations = Arrays.stream(method.getAnnotations())
    .map(Annotation::annotationType)
    .filter(t -> t.isAnnotationPresent(HttpMethod.class))
    .distinct().count();
if (httpAnnotations > 1) throw new IllegalStateException("Multiple HTTP verbs on " + method);

Prevention

When it happens

Trigger: Annotating one resource method with two HTTP verb annotations, e.g. both @GET and @POST, or a custom @HttpMethod annotation combined with a standard one, discovered while indexing the class.

Common situations: Copy-paste of annotations intending 'supports GET or POST'; a custom @HttpMethod meta-annotation whose name clashes with a built-in one; accidental duplicate annotations after merging branches.

Related errors


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