apache/cassandra · error · UnauthorizedException

Only superusers can drop a role with superuser status

Error message

Only superusers can drop a role with superuser status

What it means

Cassandra throws UnauthorizedException when a non-superuser attempts to DROP a role that has superuser status. The check only runs for roles that actually exist, to avoid caching information about nonexistent roles (CASSANDRA-9189). Only a superuser may remove another superuser role.

Source

Thrown at src/java/org/apache/cassandra/cql3/statements/DropRoleStatement.java:58

    private final RoleResource role;
    private final boolean ifExists;

    public DropRoleStatement(RoleName name, boolean ifExists)
    {
        this.role = RoleResource.role(name.getName());
        this.ifExists = ifExists;
    }

    public void authorize(ClientState state) throws UnauthorizedException
    {
        super.checkPermission(state, Permission.DROP, role);

        // We only check superuser status for existing roles to avoid
        // caching info about roles which don't exist (CASSANDRA-9189)
        if (DatabaseDescriptor.getRoleManager().isExistingRole(role)
            && Roles.hasSuperuserStatus(role)
            && !state.getUser().isSuper())
            throw new UnauthorizedException("Only superusers can drop a role with superuser status");
    }

    public void validate(ClientState state) throws RequestValidationException
    {
        // validate login here before authorize to avoid leaking user existence to anonymous users.
        state.ensureNotAnonymous();

        if (!ifExists && !DatabaseDescriptor.getRoleManager().isExistingRole(role))
            throw new InvalidRequestException(String.format("%s doesn't exist", role.getRoleName()));

        AuthenticatedUser user = state.getUser();
        if (user != null && user.getName().equals(role.getRoleName()))
            throw new InvalidRequestException("Cannot DROP primary role for current login");
    }

    public ResultMessage execute(ClientState state) throws RequestValidationException, RequestExecutionException
    {
        // not rejected in validate()

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Log in as (or assume) a superuser role and re-run the DROP ROLE statement
  2. Demote the target role first with ALTER ROLE <role> WITH SUPERUSER = false as a superuser, then drop it
  3. Grant the executing role SUPERUSER status: ALTER ROLE <you> WITH SUPERUSER = true (requires an existing superuser)

Example fix

// before
DROP ROLE old_admin; -- as non-superuser -> UnauthorizedException
// after
ALTER ROLE old_admin WITH SUPERUSER = false; -- as superuser
DROP ROLE old_admin;
Defensive patterns

Strategy: validation

Validate before calling

boolean targetIsSuperuser = Roles.hasSuperuserStatus(RoleResource.role(targetName));
boolean iAmSuper = clientState.getUser().isSuper();
if (targetIsSuperuser && !iAmSuper) throw new IllegalStateException("login as a superuser before dropping " + targetName);

Try / catch

try { session.execute("DROP ROLE " + role); } catch (UnauthorizedException e) { log.warn("need superuser to drop {}", role); }

Prevention

When it happens

Trigger: A logged-in (authenticated, non-superuser) user with sufficient permissions on the role executes DROP ROLE <role> where <role> exists and has superuser status (hasSuperuserRole option set).

Common situations: Operators with AUTHORIZE/ALTER-style permissions try to clean up or rotate old superuser accounts; mistaken assumption that DROP permission alone suffices; after a security review revoking superuser from an admin they still try to delete the role.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/bc762a282738f638. Report an issue: GitHub.