apache/cassandra · error · InvalidRequestException
Cannot set %s on a table with counters
Error message
Cannot set %s on a table with counters
What it means
Counter tables cannot have a default_time_to_live greater than zero, because TTL semantics on counters are restricted. The builder throws this error when a table containing counter columns specifies any table parameter that includes DEFAULT_TIME_TO_LIVE with a positive value.
Source
Thrown at src/java/org/apache/cassandra/cql3/statements/schema/CreateTableStatement.java:384
// Static columns only make sense if we have at least one clustering column. Otherwise everything is static anyway
if (clusteringColumns.isEmpty() && !staticColumns.isEmpty())
throw ire("Static columns are only useful (and thus allowed) if the table has at least one clustering column");
}
/*
* Counter table validation
*/
boolean hasCounters = rawColumns.values().stream().anyMatch(c -> c.rawType.isCounter());
if (hasCounters)
{
// We've handled anything that is not a PRIMARY KEY so columns only contains NON-PK columns. So
// if it's a counter table, make sure we don't have non-counter types
if (columns.values().stream().anyMatch(t -> !t.type.isCounter()))
throw ire("Cannot mix counter and non counter columns in the same table");
if (params.defaultTimeToLive > 0)
throw ire("Cannot set %s on a table with counters", TableParams.Option.DEFAULT_TIME_TO_LIVE);
}
/*
* Create the builder
*/
TableMetadata.Builder builder = TableMetadata.builder(keyspaceName, tableName);
if (attrs.hasProperty(TableAttributes.ID))
builder.id(attrs.getId());
builder.isCounter(hasCounters)
.params(params);
for (int i = 0; i < partitionKeyColumns.size(); i++)
{
ColumnProperties properties = partitionKeyColumnProperties.get(i);
ColumnIdentifier columnIdentifier = partitionKeyColumns.get(i);View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Remove or set default_time_to_live = 0 for the counter table.
- Handle expiry at the application level or move counters to a non-counter table (counters can't be mixed with other columns).
Example fix
// before CREATE TABLE t (pk int PRIMARY KEY, c counter) WITH default_time_to_live = 86400; // after CREATE TABLE t (pk int PRIMARY KEY, c counter);
Defensive patterns
Strategy: validation
Validate before calling
// Counter tables must not set a positive default_time_to_live:
boolean isCounterTable = true;
int defaultTtl = 86400;
if (isCounterTable && defaultTtl > 0) throw new IllegalArgumentException("default_time_to_live not allowed on counter tables"); Try / catch
try { session.execute(ddl); } catch (com.datastax.driver.core.exceptions.InvalidQueryException e) { if (e.getMessage().contains("Cannot set") && e.getMessage().contains("counters")) { /* remove TTL */ } else throw e; } Prevention
- Exclude default_time_to_live from counter-table templates.
- Audit DDL generators that uniformly apply TTL options.
- Handle counter expiry in application logic instead.
When it happens
Trigger: CREATE TABLE t (pk int PRIMARY KEY, c counter) WITH default_time_to_live = 86400;
Common situations: Reusing a table-options template (with TTL) for a counter table; automated schema generation applying uniform TTL settings.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- Cannot mix counter and non counter columns in the same table
- Cannot set default_time_to_live on a table with counters
- Only clustering key columns can be defined in CLUSTERING ORD
- The order of columns in the CLUSTERING ORDER directive must
- Missing CLUSTERING ORDER for column %s
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/30930b8b7b26cab9.
Report an issue: GitHub.