apache/cassandra · error · InvalidRequestException
Modification is not supported by table %s
Error message
Modification is not supported by table %s
What it means
AbstractLazyVirtualTable represents read-only lazily-computed virtual tables (e.g. caches stats, transactions). Virtual tables have no storage backing, so apply(PartitionUpdate) for INSERT/UPDATE/DELETE is rejected up front with InvalidRequestException rather than silently ignoring mutations.
Source
Thrown at src/java/org/apache/cassandra/db/virtual/AbstractLazyVirtualTable.java:774
PartitionsCollector collector = collector(dataRange, columnFilter, rowFilter, limits);
try
{
collect(collector);
}
catch (InternalDoneException ignore) {}
catch (InternalTimeoutException ignore)
{
if (onTimeout != OnTimeout.BEST_EFFORT || collector.isEmpty())
throw new ReadTimeoutException(ONE, 0, 1, false);
ClientWarn.instance.warn("Ran out of time. Returning best effort.");
}
return collector.finish();
}
@Override
public void apply(PartitionUpdate update)
{
throw new InvalidRequestException("Modification is not supported by table " + metadata);
}
@Override
public void truncate()
{
throw new InvalidRequestException("Truncation is not supported by table " + metadata);
}
@Override
public String toString()
{
return metadata().toString();
}
static Object[] composePartitionKeys(DecoratedKey decoratedKey, TableMetadata metadata)
{
if (metadata.partitionKeyColumns().size() == 1)
return new Object[] { metadata.partitionKeyType.compose(decoratedKey.getKey()) };View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Do not mutate virtual tables — they reflect live in-memory state and are read-only
- If the goal is to change runtime state, use the corresponding real mechanism (nodetool commands, system tables designed for writes, or configuration changes)
- Point the statement at the intended non-virtual table (check the keyspace: system_views vs system)
Example fix
// before DELETE FROM system_views.clients WHERE address = '127.0.0.1'; // after // use nodetool or the appropriate operational command instead $ nodetool disablebinary // example: change state via tooling, not DML
Defensive patterns
Strategy: validation
Validate before calling
if (keyspace.startsWith("system_views") || metadata.isVirtual()) throw new UnsupportedOperationException("virtual tables are read-only"); Type guard
boolean writable = t -> !t.getMetadata().isVirtual();
Try / catch
try { session.execute(dml); } catch (InvalidRequestException e) { if (e.getMessage().startsWith("Modification is not supported")) log.error("read-only virtual table"); else throw e; } Prevention
- Never generate DML against system_views.* tables
- Gate cleanup scripts on metadata().isVirtual()
- Use nodetool/config mechanisms to mutate runtime state
When it happens
Trigger: Executing INSERT, UPDATE, DELETE, or BATCH containing mutations against a read-only virtual table, e.g. `DELETE FROM system_views.clients` or `INSERT INTO system.caches (...)`.
Common situations: Scripts written for normal tables reused against system_views tables; automation trying to 'clean up' virtual table rows; mistaken use of system vs system_views tables.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Truncation is not supported by table %s
- Operator %s not supported for txn_id
- %s does not support complex column updates
- Unknown keyspace: '" + keyspaceName + "'
- Unknown object type: '" + objectType + "'. Valid types are:
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/b88d66667d9381f3.
Report an issue: GitHub.