apache/iceberg · error · NamespaceNotEmptyException
Namespace is not empty. Contains table(s).
Error message
Namespace %s is not empty. Contains %d table(s).
What it means
dropNamespace throws NamespaceNotEmptyException when the namespace still contains tables. Tables under the namespace block its deletion even if child namespaces were already removed. The message reports the number of blocking tables.
Solutions
- Drop all tables via catalog.dropTable(identifier) before dropping the namespace
- Use catalog.listTables(ns) to enumerate and handle each table (drop or rename out)
- Catch NamespaceNotEmptyException and inspect listTables to report leftover tables to the operator
Example fix
// before
catalog.dropNamespace(ns);
// after
for (TableIdentifier t : catalog.listTables(ns)) {
catalog.dropTable(t);
}
catalog.dropNamespace(ns); Defensive patterns
Strategy: validation
Validate before calling
if (!catalog.listTables(ns).isEmpty()) { throw new IllegalStateException("namespace has tables"); } Type guard
boolean dropSafe = catalog.listTables(ns).isEmpty() && catalog.listViews(ns).isEmpty();
Try / catch
try { catalog.dropNamespace(ns); } catch (NamespaceNotEmptyException e) { /* enumerate listTables, drop each, retry */ } Prevention
- Enumerate listTables(ns) and drop each table before dropNamespace
- Do not expect cascading deletes from dropNamespace
- Include table purge steps in all environment teardown jobs
When it happens
Trigger: Calling catalog.dropNamespace(ns) while listTables(ns) returns identifiers and the namespace's child-namespace check has already passed.
Common situations: Cleanup jobs that drop namespaces without purging tables first; abandoned tables from failed pipelines; users expecting dropNamespace to cascade (it does not).
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Namespace is not empty. Contains child namespace(s).
- Namespace is not empty. Contains view(s).
- Cannot delete non-empty namespace
- Cannot rename to . View already exists
- DatabaseNotEmptyException
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/8a7a670d82925ccb.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/apache/iceberg/jdbc/JdbcCatalog.java:555
}
}
@Override
public boolean dropNamespace(Namespace namespace) throws NamespaceNotEmptyException {
if (!namespaceExists(namespace)) {
return false;
}
List<Namespace> childNamespaces = listNamespaces(namespace);
if (childNamespaces != null && !childNamespaces.isEmpty()) {
throw new NamespaceNotEmptyException(
"Namespace %s is not empty. Contains %d child namespace(s).",
namespace, childNamespaces.size());
}
List<TableIdentifier> tableIdentifiers = listTables(namespace);
if (tableIdentifiers != null && !tableIdentifiers.isEmpty()) {
throw new NamespaceNotEmptyException(
"Namespace %s is not empty. Contains %d table(s).", namespace, tableIdentifiers.size());
}
if (schemaVersion != JdbcUtil.SchemaVersion.V0) {
List<TableIdentifier> viewIdentifiers = listViews(namespace);
if (viewIdentifiers != null && !viewIdentifiers.isEmpty()) {
throw new NamespaceNotEmptyException(
"Namespace %s is not empty. Contains %d view(s).", namespace, viewIdentifiers.size());
}
}
int deletedRows =
execute(
JdbcUtil.DELETE_ALL_NAMESPACE_PROPERTIES_SQL,
catalogName,
JdbcUtil.namespaceToString(namespace));
return deletedRows > 0;View on GitHub (pinned to 86d9c8fc54)