{"record":{"id":"9cf72ec8e80810c5","repo":"quarkusio/quarkus","slug":"permissionallowed-instance-that-accepts-method-ar","errorCode":null,"errorMessage":"@PermissionAllowed instance that accepts method arguments must be placed on a method","messagePattern":"@PermissionAllowed instance that accepts method arguments must be placed on a method","errorType":"exception","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java","lineNumber":1313,"sourceCode":"            }\n\n            private static boolean isNotDefaultStringPermission(Type classType) {\n                return !STRING_PERMISSION.equals(classType.name());\n            }\n        }\n\n        private static final class PermissionCacheKey {\n            private final int[] methodParamIndexes;\n            private final PermissionKey permissionKey;\n            private final boolean computed;\n            private final boolean passActionsToConstructor;\n            private final String[] methodParamConverters;\n\n            private PermissionCacheKey(PermissionKey permissionKey, AnnotationTarget securedTarget, MethodInfo constructor,\n                    PermissionConverterGenerator paramConverterGenerator) {\n                if (isComputed(permissionKey, constructor)) {\n                    if (securedTarget.kind() != AnnotationTarget.Kind.METHOD) {\n                        throw new IllegalArgumentException(\n                                \"@PermissionAllowed instance that accepts method arguments must be placed on a method\");\n                    }\n                    MethodInfo securedMethod = securedTarget.asMethod();\n\n                    // computed permission\n                    this.permissionKey = permissionKey;\n                    this.computed = true;\n                    final boolean isSecondParamStringArr = !secondParamIsNotStringArr(constructor);\n\n                    // determine if we want to pass actions param to Permission constructor\n                    if (isSecondParamStringArr && !permissionKey.isQuarkusPermission()) {\n                        int foundIx = findSecuredMethodParamIndex(securedMethod, constructor, 1,\n                                permissionKey.paramsRemainder, permissionKey.params, -1, paramConverterGenerator.index)\n                                .methodParamIdx();\n                        // if (foundIx == -1) is false then user assigned second constructor param to a method param\n                        this.passActionsToConstructor = foundIx == -1;\n                    } else {\n                        this.passActionsToConstructor = false;","sourceCodeStart":1295,"sourceCodeEnd":1331,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java#L1295-L1331","documentation":"A @PermissionsAllowed instance that consumes secured method arguments (computed permission, i.e. isComputed with param converters) must be placed on a method — the code needs MethodInfo of the secured method to capture argument values. If such a permission is placed on a class (or other non-method target), PermissionCacheKey construction throws this IllegalArgumentException at build time.","triggerScenarios":"Placing @PermissionsAllowed with a 'params' attribute referencing method arguments (computed permission) at class level, where securedTarget.kind() != METHOD.","commonSituations":"Hoisting a method-level annotation to the class to 'share' it; IDE quick-fix moving annotations; misunderstanding that class-level annotations apply to all methods and can use their params.","solutions":["Move the @PermissionsAllowed annotation with params from the class to the specific method whose arguments it needs.","If class-wide security is needed, put a param-less @PermissionsAllowed (e.g. a plain permission name backed by @PermissionChecker) at class level and keep parameterized annotations on methods."],"exampleFix":"// before\n@PermissionsAllowed(value = \"get\", params = { \"id\" })\npublic class DocumentService { ... }\n\n// after\npublic class DocumentService {\n    @PermissionsAllowed(value = \"get\", params = { \"id\" })\n    public Document get(Long id) { ... }\n}","handlingStrategy":"validation","validationCode":"// Rule: @PermissionsAllowed with params must live on a method, not a class.\n// In an ArchUnit-style test:\n// methods annotated @PermissionsAllowed with params attribute must have annotationTarget() == METHOD.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only place param-bearing @PermissionsAllowed on methods.","Use param-less annotations (or @PermissionChecker-backed ones) for class-level security.","Document the placement rule in team coding guidelines."],"tags":["quarkus","security","permissionsallowed","computed-permission"],"backgroundTag":"annotation-placement-invalid","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"}