prestodb/presto · error · PrestoException
SCHEMA_NOT_EMPTY
SCHEMA_NOT_EMPTY
Error message
Schema not empty:
What it means
dropSchema() performs a sanity check before removing the database from the metastore: if any tables or views still exist in the schema, it refuses with SCHEMA_NOT_EMPTY so users get a clearer message than the metastore's underlying failure. It lists both Iceberg tables and views in the schema.
Source
Thrown at presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergHiveMetadata.java:359
Database database = Database.builder()
.setDatabaseName(schemaName)
.setLocation(location)
.setOwnerType(USER)
.setOwnerName(session.getUser())
.build();
MetastoreContext metastoreContext = getMetastoreContext(session);
metastore.createDatabase(metastoreContext, database);
}
@Override
public void dropSchema(ConnectorSession session, String schemaName)
{
shouldRunInAutoCommitTransaction("DROP SCHEMA");
// basic sanity check to provide a better error message
if (!listTables(session, Optional.of(schemaName)).isEmpty() ||
!listViews(session, Optional.of(schemaName)).isEmpty()) {
throw new PrestoException(SCHEMA_NOT_EMPTY, "Schema not empty: " + schemaName);
}
MetastoreContext metastoreContext = getMetastoreContext(session);
metastore.dropDatabase(metastoreContext, schemaName);
}
@Override
public void renameSchema(ConnectorSession session, String source, String target)
{
shouldRunInAutoCommitTransaction("RENAME SCHEMA");
MetastoreContext metastoreContext = getMetastoreContext(session);
metastore.renameDatabase(metastoreContext, source, target);
}
@Override
public ConnectorOutputTableHandle beginCreateTable(ConnectorSession session, ConnectorTableMetadata tableMetadata, Optional<ConnectorNewTableLayout> layout)
{
SchemaTableName schemaTableName = tableMetadata.getTable();
String schemaName = schemaTableName.getSchemaName();View on GitHub (pinned to 55bb57d202)
Solutions
- List and drop all tables: run SHOW TABLES IN <schema> then DROP TABLE each one
- Also drop any views in the schema (SHOW VIEWS IN <schema>)
- Use DROP SCHEMA ... CASCADE if the engine/session supports it to drop contents along with the schema
- If tables are stale/foreign, drop them via the connector that owns them first
Example fix
// before DROP SCHEMA sales; -- Schema not empty: sales // after DROP TABLE sales.orders; DROP TABLE sales.customers; DROP SCHEMA sales;
Defensive patterns
Strategy: try-catch
Validate before calling
-- Check emptiness before dropping: SELECT count(*) FROM system.metadata.tables WHERE schema_name = 'sales'; SHOW TABLES FROM sales; SHOW VIEWS FROM sales;
Try / catch
try {
stmt.execute("DROP SCHEMA sales");
} catch (SQLException e) {
if (e.getMessage() != null && e.getMessage().contains("Schema not empty")) {
// enumerate & drop children (or use CASCADE), then retry
} else { throw e; }
} Prevention
- Script schema teardown to drop tables/views before the schema
- Prefer DROP SCHEMA ... CASCADE when supported
- Audit for orphan tables created by other engines before dropping
- Use IF EXISTS guards in cleanup scripts
When it happens
Trigger: DROP SCHEMA <name> (with or without CASCADE handled upstream) while the schema still contains at least one table or view visible to this connector; listTables or listViews returns non-empty.
Common situations: Forgetting to drop tables before DROP SCHEMA; hidden tables created by other engines that the user forgot about; a failed migration left orphaned tables in the schema.
Related errors
- Not a Hive table:
- Not an Iceberg table: ${getSchemaTableName()}
- Table not found: ${new SchemaTableName(database, tableName)}
- ICEBERG_INVALID_METADATA
- Cannot commit: stale table metadata for %s
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/6f3ebd3027396af6.
Report an issue: GitHub.