{"record":{"id":"c9ba53574da7946f","repo":"quarkusio/quarkus","slug":"only-a-single-argument-can-be-annotated-with","errorCode":null,"errorMessage":"Only a single argument can be annotated with '\" + URL + \"'. Offending method is '\" + jandexMethod.declaringClass().name() + \"#\" + jandexMethod.name()","messagePattern":"Only a single argument can be annotated with '\" \\+ URL \\+ \"'\\. Offending method is '\" \\+ jandexMethod\\.declaringClass\\(\\)\\.name\\(\\) \\+ \"#\" \\+ jandexMethod\\.name\\(\\)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java","lineNumber":1029,"sourceCode":"                                        MethodDescriptor.ofConstructor(ClientObservabilityHandler.class, String.class),\n                                        classContext.constructor.load(templatePath)));\n                    }\n\n                    // generate implementation for a method from jaxrs interface:\n                    MethodCreator methodCreator = classContext.classCreator.getMethodCreator(method.getName(),\n                            method.getSimpleReturnType(),\n                            javaMethodParameters);\n\n                    AssignableResultHandle methodTarget = methodCreator.createVariable(WebTarget.class);\n                    methodCreator.assign(methodTarget,\n                            methodCreator.readInstanceField(defaultWebTargetForMethod, methodCreator.getThis()));\n\n                    // handle the @BaseUrl annotation\n                    List<AnnotationInstance> notBodyAnnotations = jandexMethod.annotations(URL).stream()\n                            .filter(ai -> ai.target().kind() == AnnotationTarget.Kind.METHOD_PARAMETER).toList();\n                    if (!notBodyAnnotations.isEmpty()) {\n                        if (notBodyAnnotations.size() > 1) {\n                            throw new IllegalArgumentException(\n                                    \"Only a single argument can be annotated with '\" + URL\n                                            + \"'. Offending method is '\"\n                                            + jandexMethod.declaringClass().name() + \"#\" + jandexMethod.name());\n                        }\n\n                        // the idea here is to create a WebTarget that used the base URL provided by the user,\n                        // along with the paths of the REST Client class and current method\n\n                        MethodParameterInfo baseUrlMethodParam = notBodyAnnotations.get(0).target().asMethodParameter();\n                        DotName notBodyTargetType = baseUrlMethodParam.type().name();\n\n                        ResultHandle methodParam = methodCreator.getMethodParam(baseUrlMethodParam.position());\n                        AssignableResultHandle newUri = methodCreator.createVariable(java.net.URI.class);\n                        BytecodeCreator methodParamNotNull = methodCreator.ifNotNull(methodParam).trueBranch();\n\n                        if (STRING.equals(notBodyTargetType)) {\n                            methodParamNotNull.assign(newUri, methodParamNotNull.newInstance(URI_CTOR, methodParam));\n                        } else if (ResteasyReactiveDotNames.URL.equals(notBodyTargetType)) {","sourceCodeStart":1011,"sourceCodeEnd":1047,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java#L1011-L1047","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Keep exactly one @BaseUrl-annotated parameter per client method","Remove the redundant @BaseUrl from the extra parameter","If multiple URL parts are needed, pass a single java.net.URL or String parameter and build the path inside it"],"exampleFix":"// before\nString get(@BaseUrl String base, @BaseUrl String alt, String id);\n// after\nString get(@BaseUrl String base, String id);","handlingStrategy":"validation","validationCode":"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);","typeGuard":"boolean hasSingleBaseUrl(java.lang.reflect.Method m) { return Arrays.stream(m.getParameters()).filter(p -> p.isAnnotationPresent(BaseUrl.class)).count() == 1; }","tryCatchPattern":"try { client.call(); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"Only a single argument\")) { log.error(\"Remove duplicate @BaseUrl parameter\"); } throw e; }","preventionTips":["At most one @BaseUrl parameter per client method","Audit client interfaces after merges/refactors","Treat @BaseUrl as a singleton marker per method","Add an architecture test scanning client interfaces"],"tags":["quarkus","rest-client","baseurl","annotation-misuse","build-time"],"backgroundTag":"duplicate-annotation-parameter","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}