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
- 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.
- 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`.
- Log in with the intended non-protected workflow: Cassandra superusers are still subject to this protection — modify via JMX/nodetool or offline tools instead.
- 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
- Never issue DDL against system_auth (or configured auth keyspaces) from client sessions
- Change auth keyspace replication only through supported, node-local procedures
- Document that even superusers hit this guard
- Keep custom authenticator/authorizer keyspaces outside routine client workflows
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
- ACCESS TO DATACENTERS operations not supported by…
- Altering column types is no longer supported
- Cannot add a counter column to Accord table
- Cannot add new column to a COMPACT STORAGE table
- Cannot drop a table when materialized views still depend on…
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)