{"record":{"id":"1a1d24c139a260d2","repo":"quarkusio/quarkus","slug":"permissionchecker-annotation-instance-placed-on-t","errorCode":null,"errorMessage":"@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'","messagePattern":"@PermissionChecker annotation instance placed on the '(.+?)' returns 'Uni<Boolean>' and is\n                            annotated with the @Blocking annotation; if you need to block, please return 'boolean'","errorType":"exception","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java","lineNumber":156,"sourceCode":"                    throw new RuntimeException(\"Static method '\" + toString(checkerMethod)\n                            + \"' cannot be annotated with the @PermissionChecker annotation\");\n                }\n                boolean isReactive = isUniBoolean(checkerMethod);\n                if (!isReactive && !isPrimitiveBoolean(checkerMethod)) {\n                    throw new RuntimeException((\"@PermissionChecker method '%s' has return type '%s', but only \" +\n                            \"supported return types are 'boolean' and 'Uni<Boolean>'. \")\n                            .formatted(toString(checkerMethod), checkerMethod.returnType().name()));\n                }\n\n                var permissionName = annotationInstance.value().asString();\n                if (permissionName.isBlank()) {\n                    throw new IllegalArgumentException(\n                            \"@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),","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java#L138-L174","documentation":"A @PermissionChecker method returning Uni<Boolean> (reactive check) was also annotated with @Blocking. Reactive permission checkers must not block; if you need to block on an external check you must return plain boolean so Quarkus invokes it on a worker thread. This combination is rejected at build time.","triggerScenarios":"Declaring a method like @PermissionChecker(\"x\") @Blocking Uni<Boolean> check(...) — reactive return type combined with @Blocking — during the security deployment build step.","commonSituations":"Migrating a blocking permission checker to reactive (or vice versa) and leaving the old @Blocking annotation in place; cargo-culting @Blocking onto all security-related methods.","solutions":["Remove the @Blocking annotation from the Uni<Boolean>-returning permission checker","If the check must block (JDBC, remote call), change the return type from Uni<Boolean> to boolean","Split the logic: a blocking boolean checker, or a reactive Uni<Boolean> checker without @Blocking"],"exampleFix":"// before\n@PermissionChecker(\"book:read\")\n@Blocking\nUni<Boolean> canRead(Book book) { ... }\n\n// after (blocking check)\n@PermissionChecker(\"book:read\")\nboolean canRead(Book book) { ... }\n// or reactive without blocking\n@PermissionChecker(\"book:read\")\nUni<Boolean> canRead(Book book) { ... }","handlingStrategy":"validation","validationCode":"Method m = MyBean.class.getMethod(\"canRead\", Book.class);\nif (m.getAnnotation(Blocking.class) != null && Uni.class.equals(m.getReturnType())) {\n    throw new IllegalStateException(\"Reactive permission checker must not be @Blocking\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Adopt a convention: boolean return = blocking, Uni<Boolean> = never @Blocking","Grep for 'Uni<Boolean>' methods annotated @Blocking in CI","Keep permission checkers thin and non-blocking when reactive"],"tags":["quarkus","security","build-time","reactive","blocking"],"backgroundTag":"blocking-reactive-conflict","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"}