apache/cassandra · error · InvalidRequestException
A user type cannot contain counters
Error message
A user type cannot contain counters
What it means
Thrown when ALTER TYPE would add or modify a field whose type is a counter. Counter columns cannot be nested inside user-defined types in Cassandra because counters require special replication and cannot be part of composite or nested structures. The check inspects the prepared field type (`type.isCounter()`) before applying the change.
Solutions
- Use a regular counter column on a table instead of nesting it in a UDT
- Store counters in a dedicated counter table keyed by the same primary key
- Choose a non-counter numeric type (e.g. bigint) in the UDT if approximate snapshots suffice
Example fix
// before ALTER TYPE ks.stats ADD hits counter; // after CREATE TABLE ks.stat_counters (id uuid PRIMARY KEY, hits counter);
Defensive patterns
Strategy: validation
Validate before calling
if (fieldType.trim().equalsIgnoreCase("counter"))
throw new IllegalArgumentException("Counters cannot be used inside user types; use a counter table column"); Type guard
boolean isCounterField(String cqlFieldType) { return cqlFieldType.trim().equalsIgnoreCase("counter"); } Try / catch
try { session.execute(alterTypeStmt); }
catch (InvalidQueryException e) {
if ("A user type cannot contain counters".equals(e.getMessage())) {
// redesign: use a counter table instead
} else throw e;
} Prevention
- Never model counters as UDT fields; reserve counters for dedicated counter tables
- Validate generated migrations for counter field types before applying
- Document UDT field-type restrictions in schema design guidelines
When it happens
Trigger: Executing `ALTER TYPE ks.typ ADD field counter` or altering an existing field to counter type.
Common situations: Developers assuming counters behave like normal columns everywhere; porting table column definitions into UDTs; ORM/migration generators emitting counter fields inside types.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- A user type cannot contain non-frozen UDTs
- Altering field types is no longer supported
- Argument ' ' cannot be frozen; remove frozen<> modifier from
- Cannot add a counter column to Accord table
- Cannot add field to type : a field with name already exists
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/f0b77fefa6f86c82.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/cql3/statements/schema/AlterTypeStatement.java:143
@Override
public void validate(ClientState state)
{
super.validate(state);
// save the query state to use it for guardrails validation in #apply
this.state = state;
}
@Override
public boolean compatibleWith(ClusterMetadata metadata)
{
return metadata.directory.commonSerializationVersion.isAtLeast(Version.V0);
}
UserType apply(KeyspaceMetadata keyspace, UserType userType)
{
if (type.isCounter())
throw ire("A user type cannot contain counters");
if (type.isUDT() && !type.isFrozen())
throw ire("A user type cannot contain non-frozen UDTs");
if (userType.fieldPosition(fieldName) >= 0)
{
if (!ifFieldNotExists)
throw ire("Cannot add field %s to type %s: a field with name %s already exists", fieldName, userType.getCqlTypeName(), fieldName);
return userType;
}
AbstractType<?> fieldType = type.prepare(keyspaceName, keyspace.types).getType();
if (fieldType.referencesUserType(userType.name))
throw ire("Cannot add new field %s of type %s to user type %s as it would create a circular reference", fieldName, type, userType.getCqlTypeName());
Collection<TableMetadata> tablesWithTypeInPartitionKey = findTablesReferencingTypeInPartitionKey(keyspace, userType);
if (!tablesWithTypeInPartitionKey.isEmpty())
{View on GitHub (pinned to 88fd0f6a0e)