quarkusio/quarkus · error · java.lang.RuntimeException
Found @PermissionChecker annotation instance declared on the
Error message
Found @PermissionChecker annotation instance declared on the CDI bean method '%s#%s'.
The CDI bean is a dependent scoped bean, but only the '@Singleton' bean or normal scoped beans are supported What it means
A @PermissionChecker method's declaring bean cannot be @Dependent scoped: Quarkus would have no lifecycle point to destroy such instances. Only @Singleton beans or normal-scoped beans (e.g. @ApplicationScoped) are supported, so the build fails when a dependent-scoped bean hosts a permission checker.
Source
Thrown at extensions/security/deployment/src/main/java/io/quarkus/security/deployment/SecurityProcessor.java:887
.createWith(recorder.createPermissionAugmentor());
checkerBuilder.instance.getPermissionCheckers().stream().forEach(checkerMethod -> {
var checkerClassType = Type.create(checkerMethod.declaringClass().name(), Type.Kind.CLASS);
// validate permission checker method's declaring class is a CDI bean
// synthetic beans are not taken into consideration which makes them not supported
var matchingBeans = beanDiscoveryFinishedBuildItem.beanStream().assignableTo(checkerClassType).collect();
if (matchingBeans.isEmpty()) {
throw new RuntimeException(
"""
@PermissionChecker declared on method '%s', but no matching CDI bean could be found for the declaring class '%s'.
"""
.formatted(checkerMethod.name(), checkerClassType.name()));
}
// Using @Dependent is problematic because we would have to destroy beans manually at some point (which?)
matchingBeans.stream().filter(b -> BuiltinScope.DEPENDENT.getInfo().equals(b.getScope())).findFirst()
.ifPresent(bi -> {
throw new RuntimeException(
"""
Found @PermissionChecker annotation instance declared on the CDI bean method '%s#%s'.
The CDI bean is a dependent scoped bean, but only the '@Singleton' bean or normal scoped beans are supported
"""
.formatted(checkerMethod.name(), checkerClassType.name()));
});
syntheticBeanConfigurator.addInjectionPoint(checkerClassType);
});
syntheticBeanProducer.produce(syntheticBeanConfigurator.done());
// ==== Generate QuarkusPermission for each @PermissionChecker annotation instance
checkerBuilder.instance.generatePermissionCheckers(generatedClassProducer, generatedResourceProducer,
generatedServiceProviderProducer);
}
}
View on GitHub (pinned to e1c734241f)
Solutions
- Annotate the declaring class with @Singleton (no proxies needed) or a normal scope such as @ApplicationScoped.
- Remove @Dependent if explicitly present and replace it with @Singleton or @ApplicationScoped.
- Re-run the build to confirm the checker bean resolves to a supported scope.
Example fix
// before
@Dependent
public class PaymentChecker { @PermissionChecker("pay") boolean canPay() { ... } }
// after
@ApplicationScoped
public class PaymentChecker { @PermissionChecker("pay") boolean canPay() { ... } } Defensive patterns
Strategy: validation
Validate before calling
// reject @Dependent on permission checker hosts boolean bad = PaymentChecker.class.isAnnotationPresent(jakarta.enterprise.context.Dependent.class);
Prevention
- Default to @ApplicationScoped for checker classes
- Never rely on implicit dependent scope for security components
- Review scope annotations when adding @PermissionChecker
When it happens
Trigger: Declaring a @PermissionChecker method on a class with no scope annotation that is still picked up as a @Dependent bean (default scope), or explicitly annotated with @Dependent / @Transactional @Dependent combos.
Common situations: Forgetting to add a scope so the class defaults to @Dependent; using @Singleton missing and assuming @Dependent works; annotation like @WithDuplicates or custom stereotype defaulting to dependent scope.
Related errors
- @PermissionChecker declared on method '%s', but no matching
- Not possible to define the scope %s for the REST client %s
- Unable to determine if bean '${className}' is available
- @AuthorizationPolicy annotation placed on resource method '$
- Security annotation placed on resource method '${className}#
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/d329c450e5c9bac5.
Report an issue: GitHub.