apache/cassandra · error · UnauthorizedException
keyspace is not user-modifiable.
Error message
${keyspace} keyspace is not user-modifiable. What it means
Cassandra throws this UnauthorizedException when a client attempts DDL (ALTER, DROP, or CREATE) against a local system keyspace (e.g. system, system_schema, system_auth). Local system keyspaces are fully managed internally and their schema must never be modified by users, so ClientState blocks the operation before permission checks proceed.
Solutions
- Exclude all local system keyspaces (SchemaConstants.listLocalSystemKeyspaces / Schema.SYSTEM_KEYSPACE_NAMES) from your DDL scripts and migration tooling.
- If you meant to modify application data, target your own keyspace instead of a system one.
- If you need to change replication of replicated system keyspaces (system_auth, system_distributed, system_traces), use ALTER KEYSPACE with ALTER permission on a keyspace-level resource — those are handled separately.
- To change internals, adjust cassandra.yaml or use nodetool/JMX instead of CQL DDL on system keyspaces.
Example fix
// before ALTER TABLE system.local ADD extra text; // after ALTER TABLE my_app.settings ADD extra text;
Defensive patterns
Strategy: validation
Validate before calling
import org.apache.cassandra.db.SchemaConstants;
if (SchemaConstants.isLocalSystemKeyspace(keyspace))
throw new IllegalStateException("Refusing DDL on local system keyspace " + keyspace); Prevention
- Filter out system keyspaces in any tool that enumerates keyspaces before issuing DDL.
- Maintain an explicit allowlist of application keyspaces in migrations.
- Restrict DDL permissions on system keyspaces at the role level.
When it happens
Trigger: Executing CREATE/ALTER/DROP statements (or calling ClientState.ensurePermission for DDL permissions) where the target keyspace is one returned by SchemaConstants.isLocalSystemKeyspace, e.g. ALTER TABLE system.local ..., DROP KEYSPACE system_auth, or CREATE TABLE in system_schema.
Common situations: Running migration scripts or ORM auto-schema tools that blindly iterate over all keyspaces including system ones; copying application schema DDL against a cluster with system keyspaces present; attempting to 'clean up' system keyspaces manually; tools that snapshot/restore by re-creating all keyspaces.
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
- Cannot
- ACCESS TO DATACENTERS operations not supported by…
- Altering column types is no longer supported
- Bind variables are not allowed in CREATE MATERIALIZED VIEW…
- Cannot add a counter column to Accord table
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/c4df8c871dbf55f7.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/service/ClientState.java:587
for (IResource r : resources)
if (authorize(r).contains(perm))
return;
throw new UnauthorizedException(String.format("User %s has no %s permission on %s or any of its parents",
user.getName(),
perm,
resource));
}
private void preventSystemKSSchemaModification(String keyspace, DataResource resource, Permission perm)
{
// we only care about DDL statements
if (perm != Permission.ALTER && perm != Permission.DROP && perm != Permission.CREATE)
return;
// prevent ALL local system keyspace modification
if (SchemaConstants.isLocalSystemKeyspace(keyspace))
throw new UnauthorizedException(keyspace + " keyspace is not user-modifiable.");
if (SchemaConstants.isReplicatedSystemKeyspace(keyspace))
{
// allow users with sufficient privileges to alter replication params of replicated system keyspaces
if (perm == Permission.ALTER && resource.isKeyspaceLevel())
return;
// prevent all other modifications of replicated system keyspaces
throw new UnauthorizedException(String.format("Cannot %s %s", perm, resource));
}
}
public void validateLogin()
{
if (user == null)
{
throw new UnauthorizedException("You have not logged in");
}View on GitHub (pinned to 88fd0f6a0e)