{"record":{"id":"f0b77fefa6f86c82","repo":"apache/cassandra","slug":"a-user-type-cannot-contain-counters","errorCode":null,"errorMessage":"A user type cannot contain counters","messagePattern":"A user type cannot contain counters","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/statements/schema/AlterTypeStatement.java","lineNumber":143,"sourceCode":"        @Override\n        public void validate(ClientState state)\n        {\n            super.validate(state);\n\n            // save the query state to use it for guardrails validation in #apply\n            this.state = state;\n        }\n\n        @Override\n        public boolean compatibleWith(ClusterMetadata metadata)\n        {\n            return metadata.directory.commonSerializationVersion.isAtLeast(Version.V0);\n        }\n\n        UserType apply(KeyspaceMetadata keyspace, UserType userType)\n        {\n            if (type.isCounter())\n                throw ire(\"A user type cannot contain counters\");\n\n            if (type.isUDT() && !type.isFrozen())\n                throw ire(\"A user type cannot contain non-frozen UDTs\");\n\n            if (userType.fieldPosition(fieldName) >= 0)\n            {\n                if (!ifFieldNotExists)\n                    throw ire(\"Cannot add field %s to type %s: a field with name %s already exists\", fieldName, userType.getCqlTypeName(), fieldName);\n                return userType;\n            }\n\n            AbstractType<?> fieldType = type.prepare(keyspaceName, keyspace.types).getType();\n            if (fieldType.referencesUserType(userType.name))\n                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());\n\n            Collection<TableMetadata> tablesWithTypeInPartitionKey = findTablesReferencingTypeInPartitionKey(keyspace, userType);\n            if (!tablesWithTypeInPartitionKey.isEmpty())\n            {","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/statements/schema/AlterTypeStatement.java#L125-L161","documentation":"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.","triggerScenarios":"Executing `ALTER TYPE ks.typ ADD field counter` or altering an existing field to counter type.","commonSituations":"Developers assuming counters behave like normal columns everywhere; porting table column definitions into UDTs; ORM/migration generators emitting counter fields inside types.","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"],"exampleFix":"// before\nALTER TYPE ks.stats ADD hits counter;\n// after\nCREATE TABLE ks.stat_counters (id uuid PRIMARY KEY, hits counter);","handlingStrategy":"validation","validationCode":"if (fieldType.trim().equalsIgnoreCase(\"counter\"))\n    throw new IllegalArgumentException(\"Counters cannot be used inside user types; use a counter table column\");","typeGuard":"boolean isCounterField(String cqlFieldType) { return cqlFieldType.trim().equalsIgnoreCase(\"counter\"); }","tryCatchPattern":"try { session.execute(alterTypeStmt); }\ncatch (InvalidQueryException e) {\n    if (\"A user type cannot contain counters\".equals(e.getMessage())) {\n        // redesign: use a counter table instead\n    } else throw e;\n}","preventionTips":["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"],"tags":["cql","udt","counter"],"backgroundTag":"schema-validation-failed","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}