apache/iceberg · error · NamespaceNotEmptyException

Cannot drop namespace %s because it still contains non-Icebe

Error message

Cannot drop namespace %s because it still contains non-Iceberg tables

What it means

GlueCatalog.dropNamespace throws NamespaceNotEmptyException when the Glue database contains tables that are not Iceberg tables (isGlueIcebergTable returns false). Iceberg's Glue catalog guards against destroying a database holding foreign-engine tables (e.g. Hive, Spark-native) that it does not own.

Source

Thrown at aws/src/main/java/org/apache/iceberg/aws/glue/GlueCatalog.java:574

  public boolean dropNamespace(Namespace namespace) throws NamespaceNotEmptyException {
    namespaceExists(namespace);

    GetTablesResponse response =
        glue.getTables(
            GetTablesRequest.builder()
                .catalogId(awsProperties.glueCatalogId())
                .databaseName(
                    IcebergToGlueConverter.toDatabaseName(
                        namespace, awsProperties.glueCatalogSkipNameValidation()))
                .build());

    if (response.hasTableList() && !response.tableList().isEmpty()) {
      Table table = response.tableList().get(0);
      if (isGlueIcebergTable(table)) {
        throw new NamespaceNotEmptyException(
            "Cannot drop namespace %s because it still contains Iceberg tables", namespace);
      } else {
        throw new NamespaceNotEmptyException(
            "Cannot drop namespace %s because it still contains non-Iceberg tables", namespace);
      }
    }

    glue.deleteDatabase(
        DeleteDatabaseRequest.builder()
            .catalogId(awsProperties.glueCatalogId())
            .name(
                IcebergToGlueConverter.toDatabaseName(
                    namespace, awsProperties.glueCatalogSkipNameValidation()))
            .build());
    LOG.info("Dropped namespace: {}", namespace);
    // Always successful, otherwise exception is thrown
    return true;
  }

  @Override
  public boolean setProperties(Namespace namespace, Map<String, String> properties)

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Migrate or remove the non-Iceberg tables first, then retry dropNamespace.
  2. If the non-Iceberg tables are known junk, delete them directly through the Glue API/console (AWS IAM permitting), outside the Iceberg catalog.
  3. Use a dedicated Glue database for Iceberg tables so the guard never trips.
  4. Verify with glue.getTables(...) which tables remain and who owns them before deleting.

Example fix

// before
catalog.dropNamespace(Namespace.of("shared")); // contains Hive tables

// after
// remove non-Iceberg tables via Glue API first
glue.deleteTable(DeleteTableRequest.builder()
    .databaseName("shared").name("legacy_hive_tbl").build());
catalog.dropNamespace(Namespace.of("shared"));
Defensive patterns

Strategy: validation

Validate before calling

// inspect Glue tables that are not Iceberg-owned before dropping the database
GetTablesResponse r = glue.getTables(GetTablesRequest.builder().databaseName(db).build());
List<Table> foreign = r.tableList().stream()
    .filter(t -> !"ICEBERG".equals(t.parameters().get("table_type")))
    .collect(Collectors.toList());
if (!foreign.isEmpty()) {
  throw new IllegalStateException("Non-Iceberg tables present: " + foreign.stream().map(Table::name).toList());
}

Try / catch

try {
  catalog.dropNamespace(ns);
} catch (NamespaceNotEmptyException e) {
  LOG.error("Database contains non-Iceberg tables; remove them via Glue API first");
}

Prevention

When it happens

Trigger: Calling catalog.dropNamespace(ns) on a Glue database that contains tables created by other engines or frameworks — tables lacking Iceberg's table_type=ICEBERG parameters.

Common situations: Shared Glue databases used by both Hive/EMR workloads and Iceberg; mixed-use databases in data lakes; attempting to clean up a database with legacy non-Iceberg tables.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/fe8c3d29f10f26d7. Report an issue: GitHub.