apache/cassandra · error · InvalidRequestException
System keyspace '%s' is not user-modifiable
Error message
System keyspace '%s' is not user-modifiable
What it means
This InvalidRequestException is thrown when a CQL schema-altering statement (CREATE/ALTER/DROP KEYSPACE or TABLE) targets a local system keyspace such as 'system', 'system_schema', etc. Local system keyspaces are managed internally by Cassandra and must never be modified through user-issued DDL, so AlterSchemaStatement.execute rejects them before any schema transformation is attempted.
Source
Thrown at src/java/org/apache/cassandra/cql3/statements/schema/AlterSchemaStatement.java:174
{
return ImmutableSet.of();
}
/**
* Schema alteration might produce a client warning (e.g. a warning to run full repair when increading RF of a keyspace).
* This method should be used to generate them instead of calling warn() in transformation code.
*
* Only called if the transformation resulted in a non-empty diff.
*/
Set<String> clientWarnings(KeyspacesDiff diff)
{
return ImmutableSet.of();
}
public ResultMessage execute(QueryState state)
{
if (SchemaConstants.isLocalSystemKeyspace(keyspaceName))
throw ire("System keyspace '%s' is not user-modifiable", keyspaceName);
KeyspaceMetadata keyspace = Schema.instance.getKeyspaceMetadata(keyspaceName);
if (null != keyspace && keyspace.isVirtual())
throw ire("Virtual keyspace '%s' is not user-modifiable", keyspaceName);
validateKeyspaceName(keyspaceName, AlterSchemaStatement::ire);
setExecutionTimestamp(state.getTimestamp());
// Perform a 'dry-run' attempt to apply the transformation locally before submitting to the CMS. This can save a
// round trip to the CMS for things syntax errors, but also fail fast for things like configuration errors.
// Such failures may be dependent on the specific node's config (for things like guardrails/memtable
// config/etc), but executing a schema change which has already been committed by the CMS should always succeed
// or else the node cannot make progress on any subsequent metadata changes. For this reason, validation errors
// during execution are trapped and the node will fall back to safe default config wherever possible. Attempting
// to apply the SchemaTransformation at this point will catch any such error which occurs locally before
// submission to the CMS, but it can't guarantee that the statement can be applied as-is on every node in the
// cluster, as config can be heterogenous falling back to safe defaults may occur on some nodes.
ClusterMetadata metadata = ClusterMetadata.current();View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Target a user-created keyspace instead of a system/local keyspace
- If replicating system keyspace settings is intended, change cluster-level configuration or auth setup rather than issuing DDL
- Check USE <keyspace> statements in the session; switch USE to a user keyspace before running DDL
Example fix
// before
session.execute("ALTER TABLE system.size_estimates WITH gc_grace_seconds = 0");
// after
// system keyspaces are not user-modifiable; use a user keyspace
session.execute("ALTER TABLE my_app.metrics WITH gc_grace_seconds = 0"); Defensive patterns
Strategy: validation
Validate before calling
Set<String> systemKeyspaces = Set.of("system","system_schema","system_auth","system_distributed","system_traces","system_views","system_virtual_schema");
if (systemKeyspaces.contains(keyspace.toLowerCase()))
throw new IllegalArgumentException("Refusing DDL on system keyspace: " + keyspace); Type guard
boolean isUserKeyspace(String ks) {
return ks != null && !SchemaConstants.isLocalSystemKeyspace(ks);
} Try / catch
try {
session.execute(ddl);
} catch (InvalidRequestException e) {
if (e.getMessage().contains("is not user-modifiable"))
log.warn("DDL skipped: {} targets a protected keyspace", ddl);
else throw e;
} Prevention
- Never USE a system keyspace in application sessions
- Whitelist target keyspaces in migration tooling
- Filter system/virtual keyspaces when enumerating keyspaces for DDL
When it happens
Trigger: Executing any AlterSchemaStatement subclass (e.g. ALTER KEYSPACE, CREATE TABLE, DROP TABLE) whose keyspaceName resolves via SchemaConstants.isLocalSystemKeyspace, e.g. 'ALTER KEYSPACE system WITH ...' or 'CREATE TABLE system_schema.foo (...)'
Common situations: Running migration or provisioning scripts that mistakenly point DDL at 'system'/'system_schema'; tools that auto-generate DDL against a connection whose default keyspace is a system keyspace; typos like 'system_schemA' vs a real user keyspace.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- category %s not found in %s
- 'Get CIDR groups for IP' operation not supported by %s
- ACCESS TO DATACENTERS operations not supported by AllowAllNe
- frozen<> is only allowed on collections, tuples, and user-de
- Table '%s.%s' is already being dropped
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/216a05a01db2f784.
Report an issue: GitHub.