quarkusio/quarkus · error · IllegalArgumentException

Only a single argument can be annotated with '" + URL + "'.

Error message

Only a single argument can be annotated with '" + URL + "'. Offending method is '" + jandexMethod.declaringClass().name() + "#" + jandexMethod.name()

What it means

In a generated REST client method, at most one parameter may carry the @BaseUrl annotation (which supplies the request's base URL). If two or more METHOD_PARAMETER targets of @BaseUrl are found on the interface method, bytecode generation aborts with an IllegalArgumentException identifying the offending method.

Source

Thrown at extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java:1029

                                        MethodDescriptor.ofConstructor(ClientObservabilityHandler.class, String.class),
                                        classContext.constructor.load(templatePath)));
                    }

                    // generate implementation for a method from jaxrs interface:
                    MethodCreator methodCreator = classContext.classCreator.getMethodCreator(method.getName(),
                            method.getSimpleReturnType(),
                            javaMethodParameters);

                    AssignableResultHandle methodTarget = methodCreator.createVariable(WebTarget.class);
                    methodCreator.assign(methodTarget,
                            methodCreator.readInstanceField(defaultWebTargetForMethod, methodCreator.getThis()));

                    // handle the @BaseUrl annotation
                    List<AnnotationInstance> notBodyAnnotations = jandexMethod.annotations(URL).stream()
                            .filter(ai -> ai.target().kind() == AnnotationTarget.Kind.METHOD_PARAMETER).toList();
                    if (!notBodyAnnotations.isEmpty()) {
                        if (notBodyAnnotations.size() > 1) {
                            throw new IllegalArgumentException(
                                    "Only a single argument can be annotated with '" + URL
                                            + "'. Offending method is '"
                                            + jandexMethod.declaringClass().name() + "#" + jandexMethod.name());
                        }

                        // the idea here is to create a WebTarget that used the base URL provided by the user,
                        // along with the paths of the REST Client class and current method

                        MethodParameterInfo baseUrlMethodParam = notBodyAnnotations.get(0).target().asMethodParameter();
                        DotName notBodyTargetType = baseUrlMethodParam.type().name();

                        ResultHandle methodParam = methodCreator.getMethodParam(baseUrlMethodParam.position());
                        AssignableResultHandle newUri = methodCreator.createVariable(java.net.URI.class);
                        BytecodeCreator methodParamNotNull = methodCreator.ifNotNull(methodParam).trueBranch();

                        if (STRING.equals(notBodyTargetType)) {
                            methodParamNotNull.assign(newUri, methodParamNotNull.newInstance(URI_CTOR, methodParam));
                        } else if (ResteasyReactiveDotNames.URL.equals(notBodyTargetType)) {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Keep exactly one @BaseUrl-annotated parameter per client method
  2. Remove the redundant @BaseUrl from the extra parameter
  3. If multiple URL parts are needed, pass a single java.net.URL or String parameter and build the path inside it

Example fix

// before
String get(@BaseUrl String base, @BaseUrl String alt, String id);
// after
String get(@BaseUrl String base, String id);
Defensive patterns

Strategy: validation

Validate before calling

long baseUrls = Arrays.stream(method.getParameters()).filter(p -> p.isAnnotationPresent(BaseUrl.class)).count(); if (baseUrls > 1) throw new IllegalStateException("Only one @BaseUrl parameter allowed on " + method);

Type guard

boolean hasSingleBaseUrl(java.lang.reflect.Method m) { return Arrays.stream(m.getParameters()).filter(p -> p.isAnnotationPresent(BaseUrl.class)).count() == 1; }

Try / catch

try { client.call(); } catch (IllegalArgumentException e) { if (e.getMessage().contains("Only a single argument")) { log.error("Remove duplicate @BaseUrl parameter"); } throw e; }

Prevention

When it happens

Trigger: Annotating two or more parameters of the same REST client interface method with @BaseUrl, causing the notBodyAnnotations size check (> 1) to fail during client generation.

Common situations: Refactoring a client method to add another URL-like parameter without removing the original @BaseUrl; misunderstanding @BaseUrl as a per-part annotation; merging two client methods.

Related errors


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