apache/cassandra · error · UnauthorizedException

schema is protected

Error message

%s schema is protected

What it means

ClientState.ensurePermission (the resource-aware overload) refuses CREATE/ALTER/DROP on any resource in PROTECTED_AUTH_RESOURCES — the keyspaces/tables backing the authenticator, authorizer, and role manager (system_auth and configured auth keyspaces). It throws UnauthorizedException stating the schema is protected, so users cannot break the auth subsystem that governs their own access.

Solutions

  1. Perform auth-keyspace changes with internal state (or as a node-local operation), e.g. run the replication change through the auth configuration mechanism rather than client DDL.
  2. If RF change is needed, use the supported path: update cassandra.yaml auth keyspace settings and apply via tooling that operates outside user permission checks, then `nodetool repair`.
  3. Log in with the intended non-protected workflow: Cassandra superusers are still subject to this protection — modify via JMX/nodetool or offline tools instead.
  4. For custom auth, relocate auth data to a dedicated keyspace and manage it outside client sessions.

Example fix

// before
ALTER KEYSPACE system_auth WITH replication = {'class':'NetworkTopologyStrategy','dc1':3};
-- UnauthorizedException: system_auth schema is protected
// after
# run node-locally / via supported tooling, then:
nodetool repair -pr system_auth
Defensive patterns

Strategy: try-catch

Validate before calling

boolean protectedRes = resource.toString().startsWith("<keyspace system_auth>");
if (protectedRes && (perm == CREATE || perm == ALTER || perm == DROP))
    throw new IllegalArgumentException("Use node-local tooling to modify auth keyspaces");

Try / catch

try { session.execute(ddl); } catch (UnauthorizedException e) {
    if (e.getMessage().endsWith("schema is protected")) logger.error("Auth schema is guarded; use supported tooling instead");
}

Prevention

When it happens

Trigger: Executing `ALTER KEYSPACE system_auth ...`, `DROP TABLE system_auth.roles`, `CREATE TABLE system_auth.x`, or similar DDL via a client session whose permission check hits this guard.

Common situations: Operators trying to change the replication factor of system_auth with a normal user account (a common RF-fix recipe) and getting blocked; tooling attempting schema cleanup inside auth keyspaces; custom IAuthenticator/IAuthorizer configured keyspaces also fall under the guard.

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/ee8f2926cc2f5fc6. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/service/ClientState.java:505

    {
        validateKeyspace(keyspace);

        if (isInternal)
            return;

        validateLogin();

        preventSystemKSSchemaModification(keyspace, resource, perm);

        // Some system data is always readable
        if ((perm == Permission.SELECT) && READABLE_SYSTEM_RESOURCES.contains(resource))
            return;

        // Modifications to any resource upon which the authenticator, authorizer or role manager depend should not be
        // be performed by users
        if (PROTECTED_AUTH_RESOURCES.contains(resource))
            if ((perm == Permission.CREATE) || (perm == Permission.ALTER) || (perm == Permission.DROP))
                throw new UnauthorizedException(String.format("%s schema is protected", resource));

        ensurePermission(perm, resource);
    }

    public void ensurePermission(Permission perm, IResource resource)
    {
        if (!DatabaseDescriptor.getAuthorizer().requireAuthorization())
            return;

        // Access to built in functions is unrestricted
        if(resource instanceof FunctionResource && resource.hasParent())
            if (((FunctionResource)resource).getKeyspace().equals(SchemaConstants.SYSTEM_KEYSPACE_NAME))
                return;

        if (resource instanceof DataResource && isOrdinaryUser())
        {
            DataResource dataResource = (DataResource)resource;
            if (!dataResource.isRootLevel())

View on GitHub (pinned to 88fd0f6a0e)