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
- Log in as (or assume) a superuser role and re-run the DROP ROLE statement
- Demote the target role first with ALTER ROLE <role> WITH SUPERUSER = false as a superuser, then drop it
- 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
- Verify Roles.hasSuperuserStatus(target) before scripting drops
- Use IF EXISTS plus a superuser service account for role lifecycle automation
- Demote roles to non-superuser before routine cleanup
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
- You are not authorized to view superuser details
- You are not authorized to view roles granted to %s
- You aren't allowed to alter %s
- %s doesn't exist
- Cannot DROP primary role for current login
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/bc762a282738f638.
Report an issue: GitHub.