{"record":{"id":"fccd86d7d2617846","repo":"apache/cassandra","slug":"cannot-add-field-s-to-type-s-a-field-with-name","errorCode":null,"errorMessage":"Cannot add field %s to type %s: a field with name %s already exists","messagePattern":"Cannot add field (.+?) to type (.+?): a field with name (.+?) already exists","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/statements/schema/AlterTypeStatement.java","lineNumber":151,"sourceCode":"\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            {\n                throw ire(\"Cannot add new field %s of type %s to user type %s as the type is being used in partition key by the following tables: %s\",\n                          fieldName, type, userType.getCqlTypeName(),\n                          String.join(\", \", transform(tablesWithTypeInPartitionKey, TableMetadata::toString)));\n            }\n\n            Guardrails.fieldsPerUDT.guard(userType.size() + 1, userType.getNameAsString(), false, state);\n            type.validate(state, \"Field \" + fieldName);\n","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/statements/schema/AlterTypeStatement.java#L133-L169","documentation":"Thrown by ALTER TYPE ... ADD when the type already contains a field with the given name. Cassandra rejects duplicate field names within a user type unless `IF NOT EXISTS` is supplied for the field, in which case the statement is a no-op for that field. The check uses `userType.fieldPosition(fieldName) >= 0` to detect the collision.","triggerScenarios":"Executing `ALTER TYPE ks.typ ADD existing_field type` where a field with that exact name already exists in the UDT and the statement does not use `IF NOT EXISTS`.","commonSituations":"Idempotent migration scripts re-run against a cluster where the field was already added; typos reusing an existing field name; concurrent migrations adding the same field name.","solutions":["Add `IF NOT EXISTS` to make the statement idempotent: `ALTER TYPE ks.typ ADD field text IF NOT EXISTS;`","Pick a different field name for the new attribute","Check the current type definition with `DESCRIBE TYPE ks.typ;` before running the migration"],"exampleFix":"// before\nALTER TYPE ks.address ADD zip text;\n// after\nALTER TYPE ks.address ADD zip text IF NOT EXISTS;","handlingStrategy":"validation","validationCode":"Row r = session.execute(\"SELECT field_names FROM system_schema.types WHERE keyspace_name=? AND type_name=?\", ks, typeName).one();\nboolean fieldExists = r.getList(\"field_names\", String.class).stream().anyMatch(f -> f.equalsIgnoreCase(newField));\nif (fieldExists) throw new IllegalStateException(\"Field \" + newField + \" already exists in \" + ks + \".\" + typeName);","typeGuard":"boolean udtHasField(Session s, String ks, String typeName, String fieldName) {\n    Row r = s.execute(\"SELECT field_names FROM system_schema.types WHERE keyspace_name=? AND type_name=?\", ks, typeName).one();\n    return r != null && r.getList(\"field_names\", String.class).stream().anyMatch(f -> f.equalsIgnoreCase(fieldName));\n}","tryCatchPattern":"try { session.execute(alterTypeStmt); }\ncatch (InvalidQueryException e) {\n    if (e.getMessage().startsWith(\"Cannot add field \") && e.getMessage().contains(\"already exists\")) {\n        // treat as already-applied\n    } else throw e;\n}","preventionTips":["Use IF NOT EXISTS on ADD field for idempotent migrations","DESCRIBE TYPE (or system_schema.types) before adding fields","Make migration scripts track applied DDL so they do not re-run"],"tags":["cql","udt","duplicate-field"],"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"}