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

  1. List and drop all tables: run SHOW TABLES IN <schema> then DROP TABLE each one
  2. Also drop any views in the schema (SHOW VIEWS IN <schema>)
  3. Use DROP SCHEMA ... CASCADE if the engine/session supports it to drop contents along with the schema
  4. 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

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


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/6f3ebd3027396af6. Report an issue: GitHub.