{"record":{"id":"0e437f1f5d989e8c","repo":"quarkusio/quarkus","slug":"parameter-parametername-of-method-targetme","errorCode":null,"errorMessage":"Parameter '${parameterName}' of method '${targetMethod.name()} of class '${targetClass.name()}' cannot be of type '${handledExceptionType.name()}' because the method handles multiple exceptions. You can use 'java.lang.Throwable' instead.","messagePattern":"Parameter '(.+?)' of method '(.+?) of class '(.+?)' cannot be of type '(.+?)' because the method handles multiple exceptions\\. You can use 'java\\.lang\\.Throwable' instead\\.","errorType":"validation","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/generation/exceptionmappers/ServerExceptionMapperGenerator.java","lineNumber":556,"sourceCode":"    }\n\n    private static TargetMethodParamsInfo getTargetMethodParamsInfo(MethodInfo targetMethod, ClassInfo targetClass,\n            Type handledExceptionType, MethodCreator mc, ResultHandle exceptionHandle, ResultHandle contextHandle,\n            boolean handlesMultipleExceptions, Set<String> commonHierarchyOfExceptions, Set<DotName> unwrappableTypes) {\n        List<Type> parameters = targetMethod.parameterTypes();\n        ResultHandle[] targetMethodParamHandles = new ResultHandle[parameters.size()];\n        String[] parameterTypes = new String[parameters.size()];\n        // TODO: we probably want to refactor this and remove duplicate code that also exists in CustomFilterGenerator\n        for (int i = 0; i < parameters.size(); i++) {\n            Type parameter = parameters.get(i);\n            DotName paramDotName = parameter.name();\n            parameterTypes[i] = paramDotName.toString();\n            String parameterName = targetMethod.parameterName(i);\n            if (paramDotName.equals(THROWABLE)) {\n                targetMethodParamHandles[i] = exceptionHandle;\n            } else if (paramDotName.equals(handledExceptionType.name())) {\n                if (handlesMultipleExceptions && !commonHierarchyOfExceptions.contains(paramDotName.toString())) {\n                    throw new RuntimeException(\"Parameter '\" + parameterName + \"' of method '\" + targetMethod.name()\n                            + \" of class '\" + targetClass.name() + \"' cannot be of type '\" + handledExceptionType.name()\n                            + \"' because the method handles multiple exceptions. You can use '\"\n                            + Throwable.class.getName() + \"' instead.\");\n                } else {\n                    targetMethodParamHandles[i] = exceptionHandle;\n                }\n            } else if (commonHierarchyOfExceptions.contains(paramDotName.toString())) {\n                targetMethodParamHandles[i] = exceptionHandle;\n            } else if (paramDotName.equals(handledExceptionType.name())) {\n                targetMethodParamHandles[i] = exceptionHandle;\n            } else if (CONTAINER_REQUEST_CONTEXT.equals(paramDotName)\n                    || QUARKUS_REST_CONTAINER_REQUEST_CONTEXT.equals(paramDotName)) {\n                targetMethodParamHandles[i] = mc.invokeVirtualMethod(\n                        ofMethod(ResteasyReactiveRequestContext.class.getName(), \"getContainerRequestContext\",\n                                ContainerRequestContextImpl.class),\n                        contextHandle);\n            } else if (SERVER_REQUEST_CONTEXT.equals(paramDotName)) {\n                targetMethodParamHandles[i] = contextHandle;","sourceCodeStart":538,"sourceCodeEnd":574,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/generation/exceptionmappers/ServerExceptionMapperGenerator.java#L538-L574","documentation":"When a @ServerExceptionMapper handles multiple exception types (a common hierarchy was deduced for several @ServerExceptionMapper values), generated code passes the caught Throwable as the mapped exception parameter. A parameter typed as a SPECIFIC exception subtype cannot be safely used unless it is part of the common hierarchy of all handled exceptions, so a RuntimeException is thrown at build time.","triggerScenarios":"A mapper method (e.g. @ServerExceptionMapper({A.class, B.class})) where A and B are unrelated and the method has a parameter typed as A (or B, or a subtype) that is not java.lang.Throwable or a member of the deduced common exception hierarchy.","commonSituations":"Declaring multiple exception types in @ServerExceptionMapper while keeping a specific exception parameter; merging two mappers into one without changing the parameter type; misunderstanding that only Throwable works for multi-exception mappers.","solutions":["Change the exception parameter type to java.lang.Throwable and instanceof-cast inside the method","Remove the multiple exception values and create one @ServerExceptionMapper method per specific exception type","Ensure the parameter type is a common ancestor of all listed exception types so it appears in the deduced hierarchy"],"exampleFix":"// before\n@ServerExceptionMapper({NotFoundException.class, BadRequestException.class})\npublic Response map(NotFoundException e) {...}\n// after\n@ServerExceptionMapper({NotFoundException.class, BadRequestException.class})\npublic Response map(Throwable e) {...}","handlingStrategy":"type-guard","validationCode":"// For multi-exception mappers, require Throwable (or a common ancestor) parameter\nfor (Method m : multiExceptionMappers) {\n  for (Class<?> p : m.getParameterTypes()) {\n    if (Throwable.class.isAssignableFrom(p) && p != Throwable.class && !isCommonAncestorOfAllValues(p, m))\n      throw new IllegalStateException(m + \": parameter \" + p + \" must be Throwable or a common ancestor\");\n  }\n}","typeGuard":"boolean safeMultiExceptionParam(Method m, Class<?> param) {\n  if (param == Throwable.class) return true;\n  ClassInfo ci = indexedClass(param);\n  return commonHierarchyOfExceptions.containsAll(\n    java.util.Arrays.stream(m.getAnnotation(ServerExceptionMapper.class).value())\n      .map(Class::getName).collect(java.util.stream.Collectors.toSet())\n      .stream().filter(n -> !ci.name().toString().equals(n)).toList()) || param == Throwable.class;\n}","tryCatchPattern":"// In the mapper body, narrow the Throwable safely:\nif (e instanceof NotFoundException nfe) { ... } else if (e instanceof BadRequestException bre) { ... }","preventionTips":["Use java.lang.Throwable as the parameter whenever @ServerExceptionMapper lists multiple exceptions","Create one mapper method per exception type for strongly-typed parameters","Check that the parameter type is a common ancestor of all listed exception types"],"tags":["quarkus","resteasy-reactive","serverexceptionmapper","build-time"],"backgroundTag":"exception-mapper-parameter-validation","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}