{"record":{"id":"adbe4494a9e5b7b9","repo":"quarkusio/quarkus","slug":"no-s-formal-parameter-name-matches-s-permiss","errorCode":null,"errorMessage":"No '%s' formal parameter name matches '%s' Permission %s parameter name '%s'","messagePattern":"No '(.+?)' formal parameter name matches '(.+?)' Permission (.+?) parameter name '(.+?)'","errorType":"exception","errorClass":"java.lang.RuntimeException","httpStatus":null,"severity":"error","filePath":"extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java","lineNumber":1439,"sourceCode":"\n            private static SecMethodAndPermCtorIdx[] matchPermCtorParamIdxBasedOnNameMatch(MethodInfo securedMethod,\n                    MethodInfo constructor, boolean passActionsToConstructor, String[] requiredMethodParams,\n                    String[] requiredParamsRemainder, IndexView index, boolean isQuarkusPermission,\n                    MethodInfo permissionChecker) {\n                // assign method param to each constructor param; it's not one-to-one function (AKA injection)\n                final int nonMethodParams = (passActionsToConstructor ? 2 : 1);\n                final var matches = new SecMethodAndPermCtorIdx[constructor.parametersCount() - nonMethodParams];\n                for (int i = nonMethodParams; i < constructor.parametersCount(); i++) {\n                    // find index for exact name match between constructor and method param\n                    var match = findSecuredMethodParamIndex(securedMethod, constructor, i,\n                            requiredParamsRemainder, requiredMethodParams, nonMethodParams, index);\n                    matches[i - nonMethodParams] = match;\n                    if (match.methodParamIdx() == -1) {\n                        final String constructorParamName = constructor.parameterName(i);\n                        final String matchTarget = isQuarkusPermission\n                                ? PermissionSecurityChecksBuilder.toString(permissionChecker)\n                                : constructor.declaringClass().name().toString();\n                        throw new RuntimeException(String.format(\n                                \"No '%s' formal parameter name matches '%s' Permission %s parameter name '%s'\",\n                                PermissionSecurityChecksBuilder.toString(securedMethod), matchTarget,\n                                isQuarkusPermission ? \"checker\" : \"constructor\", constructorParamName));\n                    }\n                }\n                return matches;\n            }\n\n            private static SecMethodAndPermCtorIdx findSecuredMethodParamIndex(MethodInfo securedMethod, MethodInfo constructor,\n                    int constructorIx, String[] requiredParamsRemainder, String[] requiredParams, int nonMethodParams,\n                    IndexView index) {\n                final String constructorParamName = constructor.parameterName(constructorIx);\n                final int constructorParamIdx = constructorIx - nonMethodParams;\n\n                if (requiredParams != null && requiredParams.length != 0) {\n                    // user specified explicitly parameter names with @PermissionsAllowed(params = \"some.name\")\n                    for (int i = 0; i < securedMethod.parametersCount(); i++) {\n                        var methodParamName = securedMethod.parameterName(i);","sourceCodeStart":1421,"sourceCodeEnd":1457,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java#L1421-L1457","documentation":"In the reverse direction, Quarkus iterates the parameters of the constructor (or Quarkus permission checker method) and must find a matching formal parameter on the secured method. When a constructor/checker parameter (e.g. of the custom Permission class) has no corresponding named formal parameter on the secured method, match.methodParamIdx() == -1 and this RuntimeException is thrown, naming the secured method, the match target, whether it was a checker or constructor, and the unmatched parameter name.","triggerScenarios":"A custom Permission class constructor declares a parameter (e.g. 'owner') that no @PermissionsAllowed params entry or secured-method parameter satisfies, so the permission cannot be built with values from the secured method invocation.","commonSituations":"Custom Permission constructor extended with a new parameter without updating @PermissionsAllowed params; compile without -parameters losing formal names; reusing a Permission class across methods whose signatures differ.","solutions":["Add the missing name to @PermissionsAllowed params (or as a secured method parameter) so the constructor/checker parameter can be matched, e.g. params = { \"owner\" }.","Remove the extra parameter from the custom Permission constructor if it is not needed.","Ensure the secured method is compiled with -parameters so formal parameter names are available for matching."],"exampleFix":"// before\n@PermissionsAllowed(value = \"get\", clazz = GetPermission.class) // GetPermission(name, ownerId) — ownerId unmatched\npublic Document get(Long id) { ... }\n\n// after\n@PermissionsAllowed(value = \"get\", clazz = GetPermission.class, params = { \"id\" })\npublic Document get(Long id) { ... }","handlingStrategy":"validation","validationCode":"// Every custom Permission constructor parameter must be satisfied via @PermissionsAllowed params:\n// for (var p : permissionConstructor.getParameters())\n//     assert annotationParams.contains(p.getName()) : p.getName() + \" unmatched on secured method\";","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep custom Permission constructor signatures minimal and always mirrored in @PermissionsAllowed params.","Reuse a Permission class only on methods providing all its parameters.","Compile with -parameters so names are retained for matching."],"tags":["quarkus","security","params-mapping","custom-permission"],"backgroundTag":"parameter-name-mismatch","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"}