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

  1. Target a user-created keyspace instead of a system/local keyspace
  2. If replicating system keyspace settings is intended, change cluster-level configuration or auth setup rather than issuing DDL
  3. 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

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


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/216a05a01db2f784. Report an issue: GitHub.