quarkusio/quarkus · error · java.lang.RuntimeException
No '%s' formal parameter name matches '%s' Permission %s par
Error message
No '%s' formal parameter name matches '%s' Permission %s parameter name '%s'
What it means
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.
Source
Thrown at extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java:1439
private static SecMethodAndPermCtorIdx[] matchPermCtorParamIdxBasedOnNameMatch(MethodInfo securedMethod,
MethodInfo constructor, boolean passActionsToConstructor, String[] requiredMethodParams,
String[] requiredParamsRemainder, IndexView index, boolean isQuarkusPermission,
MethodInfo permissionChecker) {
// assign method param to each constructor param; it's not one-to-one function (AKA injection)
final int nonMethodParams = (passActionsToConstructor ? 2 : 1);
final var matches = new SecMethodAndPermCtorIdx[constructor.parametersCount() - nonMethodParams];
for (int i = nonMethodParams; i < constructor.parametersCount(); i++) {
// find index for exact name match between constructor and method param
var match = findSecuredMethodParamIndex(securedMethod, constructor, i,
requiredParamsRemainder, requiredMethodParams, nonMethodParams, index);
matches[i - nonMethodParams] = match;
if (match.methodParamIdx() == -1) {
final String constructorParamName = constructor.parameterName(i);
final String matchTarget = isQuarkusPermission
? PermissionSecurityChecksBuilder.toString(permissionChecker)
: constructor.declaringClass().name().toString();
throw new RuntimeException(String.format(
"No '%s' formal parameter name matches '%s' Permission %s parameter name '%s'",
PermissionSecurityChecksBuilder.toString(securedMethod), matchTarget,
isQuarkusPermission ? "checker" : "constructor", constructorParamName));
}
}
return matches;
}
private static SecMethodAndPermCtorIdx findSecuredMethodParamIndex(MethodInfo securedMethod, MethodInfo constructor,
int constructorIx, String[] requiredParamsRemainder, String[] requiredParams, int nonMethodParams,
IndexView index) {
final String constructorParamName = constructor.parameterName(constructorIx);
final int constructorParamIdx = constructorIx - nonMethodParams;
if (requiredParams != null && requiredParams.length != 0) {
// user specified explicitly parameter names with @PermissionsAllowed(params = "some.name")
for (int i = 0; i < securedMethod.parametersCount(); i++) {
var methodParamName = securedMethod.parameterName(i);View on GitHub (pinned to e1c734241f)
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.
Example fix
// before
@PermissionsAllowed(value = "get", clazz = GetPermission.class) // GetPermission(name, ownerId) — ownerId unmatched
public Document get(Long id) { ... }
// after
@PermissionsAllowed(value = "get", clazz = GetPermission.class, params = { "id" })
public Document get(Long id) { ... } Defensive patterns
Strategy: validation
Validate before calling
// Every custom Permission constructor parameter must be satisfied via @PermissionsAllowed params: // for (var p : permissionConstructor.getParameters()) // assert annotationParams.contains(p.getName()) : p.getName() + " unmatched on secured method";
Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- @PermissionChecker '%s' matches permission '%s' and actions
- Parameter '%s' specified via @PermissionsAllowed#params on s
- @PermissionsAllowed annotation placed on method '%s' has 'pa
- Cannot transform exception ${exception}
- Unable to determine if bean '${className}' is available
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/adbe4494a9e5b7b9.
Report an issue: GitHub.