{"record":{"id":"8bcd25095d464a57","repo":"quarkusio/quarkus","slug":"detected-two-permissionchecker-annotations-with-s","errorCode":null,"errorMessage":"Detected two @PermissionChecker annotations with same value '%s', annotated methods are:\n                            - %s\n                            - %s\n                            ","messagePattern":"Detected two @PermissionChecker annotations with same value '(.+?)', annotated methods are:\n                            - (.+?)\n                            - (.+?)\n                            ","errorType":"exception","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java","lineNumber":169,"sourceCode":"                            \"@PermissionChecker annotation placed on the '%s' attribute 'value' must not be blank\"\n                                    .formatted(toString(checkerMethod)));\n                }\n                boolean isBlocking = checkerMethod.hasDeclaredAnnotation(BLOCKING);\n                if (isBlocking && isReactive) {\n                    throw new IllegalArgumentException(\"\"\"\n                            @PermissionChecker annotation instance placed on the '%s' returns 'Uni<Boolean>' and is\n                            annotated with the @Blocking annotation; if you need to block, please return 'boolean'\n                            \"\"\".formatted(toString(checkerMethod)));\n                }\n\n                var generatedPermissionClassName = getGeneratedPermissionName(checkerMethod, permissionCheckerIndex++);\n                var methodParamMappers = new MethodParameterMapper[checkerMethod.parametersCount()];\n                var generatedPermissionConstructor = getGeneratedPermissionConstructor(checkerMethod, methodParamMappers);\n                var checkerMetadata = new PermissionCheckerMetadata(checkerMethod, generatedPermissionClassName,\n                        isReactive, generatedPermissionConstructor, methodParamMappers, isBlocking);\n\n                if (permissionCheckers.containsKey(permissionName)) {\n                    throw new IllegalArgumentException(\"\"\"\n                            Detected two @PermissionChecker annotations with same value '%s', annotated methods are:\n                            - %s\n                            - %s\n                            \"\"\"\n                            .formatted(annotationInstance.value().asString(), toString(checkerMethod),\n                                    toString(permissionCheckers.get(permissionName).checkerMethod())));\n                }\n\n                permissionCheckers.put(permissionName, checkerMetadata);\n            }\n            return permissionCheckers;\n        }\n\n        private static boolean isUniBoolean(MethodInfo checkerMethod) {\n            if (checkerMethod.returnType().kind() == Type.Kind.PARAMETERIZED_TYPE) {\n                var parametrizedType = checkerMethod.returnType().asParameterizedType();\n                boolean returnsUni = UNI.equals(parametrizedType.name());\n                boolean booleanArg = parametrizedType.arguments().size() == 1","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java#L151-L187","documentation":"Two methods were annotated with @PermissionChecker using the same 'value' permission name. Quarkus registers one generated Permission class per checker, keyed by permission name, so duplicates are ambiguous and rejected at build time.","triggerScenarios":"Declaring @PermissionChecker(\"can-read\") on two different methods (in the same or different beans); both are discovered by the Jandex index during the security deployment step.","commonSituations":"Duplicating a checker method in a subclass or copied bean without renaming the permission; renaming a method but not its permission value; merging branches that both added the same permission name.","solutions":["Give each @PermissionChecker a unique 'value'","Delete the redundant checker method if two methods implement the same check","If both are needed for different resources, encode the distinction in the name, e.g. 'book:read' vs 'author:read'"],"exampleFix":"// before\n@PermissionChecker(\"can-read\") boolean canReadBook(Book b) {...}\n@PermissionChecker(\"can-read\") boolean canReadAuthor(Author a) {...}\n\n// after\n@PermissionChecker(\"book:read\") boolean canReadBook(Book b) {...}\n@PermissionChecker(\"author:read\") boolean canReadAuthor(Author a) {...}","handlingStrategy":"validation","validationCode":"// collect values at startup-test time\nSet<String> seen = new HashSet<>();\nfor (Method m : MyBeans.class.getDeclaredMethods()) {\n    PermissionChecker pc = m.getAnnotation(PermissionChecker.class);\n    if (pc != null && !seen.add(pc.value())) throw new IllegalStateException(\"Duplicate @PermissionChecker value: \" + pc.value());\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Centralize permission names in an enum/constants class","Use resource:action naming (book:read) to keep names unique","Add a unit test scanning the classpath for duplicate permission values"],"tags":["quarkus","security","build-time","duplicate"],"backgroundTag":"duplicate-permission-name","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"}