quarkusio/quarkus · error · IllegalStateException

QuarkusPermission should never be assigned to a SecurityIden

Error message

QuarkusPermission should never be assigned to a SecurityIdentity. This permission can only be set to the @PermissionsAllowed#permission attribute by Quarkus itself.

What it means

QuarkusPermission is an internal Permission marker placed inside @PermissionsAllowed checks to represent arbitrary action strings. Its implies() is intentionally unimplemented: it should never be the possessed permission of a SecurityIdentity, so any attempt to use it for an authorization decision throws IllegalStateException.

Source

Thrown at extensions/security/runtime/src/main/java/io/quarkus/security/runtime/QuarkusPermission.java:104

        try {
            if (isReactive()) {
                return isGrantedUni(identity);
            } else {
                return Uni.createFrom().item(isGranted(identity));
            }
        } catch (Throwable throwable) {
            return Uni.createFrom().failure(throwable);
        }
    }

    /**
     * @throws IllegalStateException for this permission can only be set to the {@link PermissionsAllowed#permission()}
     */
    @Override
    public final boolean implies(Permission requiredPermission) {
        // possessed permission implies required permission
        // this is required permission, not the possessed one
        throw new IllegalStateException("QuarkusPermission should never be assigned to a SecurityIdentity. "
                + "This permission can only be set to the @PermissionsAllowed#permission attribute by Quarkus itself.");
    }

    @Override
    public final String getActions() {
        return "";
    }

    @Override
    public final boolean equals(Object object) {
        return this == object;
    }

    @Override
    public final int hashCode() {
        return Objects.hash(toString());
    }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Never add QuarkusPermission instances to a SecurityIdentity; use real Permission implementations (BasicPermission subclasses or custom ones) for possessed permissions.
  2. In augmentors/filters, filter out QuarkusPermission instances when copying permission collections.
  3. If you need @PermissionsAllowed semantics for identity checks, use PermissionVerifier/permission checkers instead of the internal permission class.

Example fix

// before
identity.addPermission(new QuarkusPermission("read"));
// after
identity.addPermission(new BasicPermission("app") {
    { setName("read"); }
});
Defensive patterns

Strategy: type-guard

Validate before calling

// filter internal permissions out before attaching to an identity
Permission[] safe = Stream.of(permissions)
    .filter(p -> !(p instanceof QuarkusPermission))
    .toArray(Permission[]::new);

Type guard

boolean isAssignable(Permission possessed, Permission required) {
    return !(possessed instanceof QuarkusPermission) && possessed.implies(required);
}

Prevention

When it happens

Trigger: Adding a QuarkusPermission to a SecurityIdentity (e.g. via identity.addPermission(new QuarkusPermission(...))) or a custom SecurityIdentityAugmentor that propagates it; then an authorization check calls implies() on it.

Common situations: Custom identity augmentors copying permissions blindly from PermissionsAllowed metadata; reflection-based code that recreates permissions from annotation values; debugging code that prints/adds all permissions of a check.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/cc21a958cbf5f506. Report an issue: GitHub.