{"record":{"id":"ebb7991a31848567","repo":"quarkusio/quarkus","slug":"permission-constructor-s-first-argument-must-be","errorCode":null,"errorMessage":"Permission constructor '%s' first argument must be '%s'","messagePattern":"Permission constructor '(.+?)' first argument must be '(.+?)'","errorType":"exception","errorClass":"java.lang.RuntimeException","httpStatus":null,"severity":"error","filePath":"extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java","lineNumber":401,"sourceCode":"                                // to validate it\n                                classSignatureToConstructor.put(key.classSignature(),\n                                        key.permissionChecker.quarkusPermissionConstructor());\n                                permissionCheckers.remove(key.permissionChecker);\n                                continue;\n                            }\n\n                            // validate permission class\n                            final ClassInfo clazz = index.getClassByName(key.clazz.name());\n                            Objects.requireNonNull(clazz);\n                            if (clazz.constructors().size() != 1) {\n                                throw new RuntimeException(\n                                        String.format(\"Permission class '%s' has %d constructors, exactly one is allowed\",\n                                                key.classSignature(), clazz.constructors().size()));\n                            }\n                            var constructor = clazz.constructors().get(0);\n                            // first constructor parameter must be permission name\n                            if (constructor.parametersCount() == 0 || !STRING.equals(constructor.parameterType(0).name())) {\n                                throw new RuntimeException(\n                                        String.format(\"Permission constructor '%s' first argument must be '%s'\",\n                                                clazz.name().toString(), String.class.getName()));\n                            }\n                            // rest of validation needs to be done for computed classes only and per each secured method\n                            // therefore we do it later\n\n                            // cache validation result\n                            classSignatureToConstructor.put(key.classSignature(), constructor);\n                        }\n                    }\n                }\n            }\n            if (!permissionCheckers.isEmpty()) {\n                if (permissionCheckers.size() > 1) {\n                    throw new RuntimeException(\"\"\"\n                            Found @PermissionChecker annotation instances that authorize the '%s' permissions, however\n                            no @PermissionsAllowed annotation instance requires these permissions\n                            \"\"\".formatted(String.join(\",\", permissionCheckers.values())));","sourceCodeStart":383,"sourceCodeEnd":419,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java#L383-L419","documentation":"The single constructor of a custom Permission class must accept the permission name as its first parameter of type java.lang.String, since Quarkus instantiates it with the @PermissionsAllowed value as the first argument. A constructor with no parameters or a non-String first parameter is rejected at build time.","triggerScenarios":"Defining a permission class whose sole constructor is MyPerm(Book b) or MyPerm() and referencing it from @PermissionsAllowed; validated when validatePermissionClasses inspects constructor.parameterType(0).","commonSituations":"Modeling permissions around the checked resource only and omitting the name parameter; following an outdated tutorial predating the name-parameter requirement.","solutions":["Add a String permission-name parameter as the first constructor argument","Reorder constructor parameters so String comes first","If no name is meaningful, still accept it and ignore/store it in the constructor"],"exampleFix":"// before\npublic class MyPerm implements Permission {\n    public MyPerm(Book b) {...}\n}\n\n// after\npublic class MyPerm implements Permission {\n    public MyPerm(String name, Book b) { ... }\n}","handlingStrategy":"validation","validationCode":"Constructor<?> c = MyPerm.class.getConstructors()[0];\nif (c.getParameterCount() == 0 || !c.getParameterTypes()[0].equals(String.class))\n    throw new IllegalStateException(\"Permission constructor first parameter must be java.lang.String\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always model permissions as (String name, <secured params>...)","Copy the official Quarkus custom-permission example as a template","Add a reflection test asserting the constructor signature"],"tags":["quarkus","security","build-time","constructor","permission-class"],"backgroundTag":"invalid-permission-class","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"}