{"record":{"id":"bce531b0867a8e33","repo":"apache/cassandra","slug":"cannot-drop-user-type-s-s-as-it-is-still-used-bce531","errorCode":null,"errorMessage":"Cannot drop user type '%s.%s' as it is still used by tables %s","messagePattern":"Cannot drop user type '(.+?)\\.(.+?)' as it is still used by tables (.+?)","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/statements/schema/DropTypeStatement.java","lineNumber":115,"sourceCode":"                      keyspaceName,\n                      typeName,\n                      join(\", \", transform(functions, f -> f.name().toString())));\n        }\n\n        Iterable<UserType> types = keyspace.types.referencingUserType(name);\n        if (!isEmpty(types))\n        {\n            throw ire(\"Cannot drop user type '%s.%s' as it is still used by user types %s\",\n                      keyspaceName,\n                      typeName,\n                      join(\", \", transform(types, UserType::getNameAsString)));\n\n        }\n\n        Iterable<TableMetadata> tables = keyspace.tables.referencingUserType(name);\n        if (!isEmpty(tables))\n        {\n            throw ire(\"Cannot drop user type '%s.%s' as it is still used by tables %s\",\n                      keyspaceName,\n                      typeName,\n                      join(\", \", transform(tables, t -> t.name)));\n        }\n\n        return schema.withAddedOrUpdated(keyspace.withSwapped(keyspace.types.without(type)));\n    }\n\n    SchemaChange schemaChangeEvent(KeyspacesDiff diff)\n    {\n        return new SchemaChange(Change.DROPPED, Target.TYPE, keyspaceName, typeName);\n    }\n\n    public void authorize(ClientState client)\n    {\n        client.ensureAllTablesPermission(keyspaceName, Permission.DROP);\n    }\n","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/statements/schema/DropTypeStatement.java#L97-L133","documentation":"The user-defined type is still referenced by one or more table columns, so Cassandra refuses to drop it. Tables may reference the type directly or through nested UDTs, and dropping it would corrupt those table schemas.","triggerScenarios":"DROP TYPE on a UDT while keyspace.tables.referencingUserType(name) is non-empty — any table with a column (including clustering/key columns or nested UDT fields) of that type.","commonSituations":"Dropping legacy UDTs while old tables still use them; migrations that migrate data off a type but forget a table; blind cleanup scripts.","solutions":["Identify the listed tables and migrate/drop or ALTER them to stop using the type, then reissue DROP TYPE","Search system_schema.columns and UDT fields for the type before cleanup","If the data must be preserved, create a replacement table with the new schema and copy data over"],"exampleFix":"// before\nDROP TYPE ks.geo;\n// after\nALTER TABLE ks.sites DROP location;  -- stop using the type\nDROP TYPE ks.geo;","handlingStrategy":"validation","validationCode":"var cols = session.execute(\"SELECT table_name, column_name FROM system_schema.columns WHERE keyspace_name=?\", ks);\n// match type columns against the UDT name, including nested UDT field types","typeGuard":null,"tryCatchPattern":"try { session.execute(\"DROP TYPE \" + ks + \".\" + type); } catch (InvalidRequest e) { if (e.getMessage().contains(\"still used by tables\")) migrateTablesFirst(); else throw e; }","preventionTips":["Check system_schema.columns (and nested UDT fields) before dropping a type","Plan table migrations before UDT cleanup","Keep UDT-to-table dependency documentation in schema migrations"],"tags":["cassandra","cql","udt","dependency"],"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"}