apache/iceberg · error · NamespaceNotEmptyException

Cannot drop namespace %s because it still contains Iceberg t

Error message

Cannot drop namespace %s because it still contains Iceberg tables

What it means

GlueCatalog.dropNamespace throws NamespaceNotEmptyException when Glue's GetTables for the database returns at least one table whose parameters identify it as an Iceberg table. Iceberg refuses to drop a namespace that still contains Iceberg tables to prevent silent data loss.

Source

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

  }

  @Override
  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;
  }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Drop all Iceberg tables first: iterate catalog.listTables(ns) and call dropTable on each, then drop the namespace.
  2. Use dropTable(table, true) purge carefully only if the underlying data should also be deleted.
  3. If tables were already removed from Iceberg but stale entries remain in Glue, delete the orphan Glue table entries via the AWS console/API.
  4. Confirm you are dropping the intended database — the non-empty check may be catching a live production database.

Example fix

// before
catalog.dropNamespace(Namespace.of("staging"));

// after
Namespace ns = Namespace.of("staging");
for (TableIdentifier t : catalog.listTables(ns)) {
  catalog.dropTable(t);
}
catalog.dropNamespace(ns);
Defensive patterns

Strategy: validation

Validate before calling

Namespace ns = Namespace.of("staging");
if (!catalog.listTables(ns).isEmpty()) {
  throw new IllegalStateException("Namespace " + ns + " still has tables; drop them first");
}

Try / catch

try {
  catalog.dropNamespace(ns);
} catch (NamespaceNotEmptyException e) {
  catalog.listTables(ns).forEach(catalog::dropTable);
  catalog.dropNamespace(ns);
}

Prevention

When it happens

Trigger: Calling catalog.dropNamespace(ns) while the Glue database still contains Iceberg tables registered with metadata_location parameters.

Common situations: Cleanup scripts dropping databases without listing tables first; partial pipeline teardowns that deleted some but not all tables; forgetting that views/tables created by other engines in the same database block the drop.

Related errors


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