apache/iceberg · error · NamespaceNotEmptyException
Namespace %s is not empty.
Error message
Namespace %s is not empty.
What it means
HadoopCatalog.dropNamespace throws NamespaceNotEmptyException when the namespace directory still contains any entry (table directories, sub-namespaces, or stray files). The Hadoop catalog refuses to recursively delete namespaces to prevent accidental data loss.
Source
Thrown at core/src/main/java/org/apache/iceberg/hadoop/HadoopCatalog.java:345
}
private Namespace append(Namespace ns, String name) {
String[] levels = Arrays.copyOfRange(ns.levels(), 0, ns.levels().length + 1);
levels[ns.levels().length] = name;
return Namespace.of(levels);
}
@Override
public boolean dropNamespace(Namespace namespace) {
Path nsPath = new Path(warehouseLocation, SLASH.join(namespace.levels()));
if (!isNamespace(nsPath) || namespace.isEmpty()) {
return false;
}
try {
if (fs.listStatusIterator(nsPath).hasNext()) {
throw new NamespaceNotEmptyException("Namespace %s is not empty.", namespace);
}
return fs.delete(nsPath, false /* recursive */);
} catch (IOException e) {
throw new RuntimeIOException(e, "Namespace delete failed: %s", namespace);
}
}
@Override
public boolean setProperties(Namespace namespace, Map<String, String> properties) {
throw new UnsupportedOperationException(
"Cannot set namespace properties " + namespace + " : setProperties is not supported");
}
@Override
public boolean removeProperties(Namespace namespace, Set<String> properties) {
throw new UnsupportedOperationException(
"Cannot remove properties " + namespace + " : removeProperties is not supported");View on GitHub (pinned to 86d9c8fc54)
Solutions
- Drop all tables in the namespace first (loop over listTables and call dropTable).
- Recursively drop sub-namespaces via listNamespaces.
- Inspect the directory for stray/non-Iceberg files and remove or relocate them (only if safe).
- Catch NamespaceNotEmptyException and report which children remain to the operator.
Example fix
// before
catalog.dropNamespace(ns);
// after: empty it first
catalog.listTables(ns).forEach(t -> catalog.dropTable(t, true));
catalog.listNamespaces(ns).forEach(catalog::dropNamespace);
if (!catalog.listTables(ns).isEmpty() || !catalog.listNamespaces(ns).isEmpty()) {
throw new IllegalStateException("Namespace still not empty: " + ns);
}
catalog.dropNamespace(ns); Defensive patterns
Strategy: validation
Validate before calling
if (!catalog.listTables(ns).isEmpty() || !catalog.listNamespaces(ns).isEmpty()) { throw new IllegalStateException("Namespace not empty: " + ns); } Try / catch
try { catalog.dropNamespace(ns); } catch (NamespaceNotEmptyException e) { // drop children first, then retry } Prevention
- Always drop tables/sub-namespaces before the namespace
- Scan for stray staging/hidden files in namespace dirs
- Wrap drop flows in a 'drop namespace recursively' helper
When it happens
Trigger: Calling catalog.dropNamespace(namespace) when warehouseLocation/<levels> is non-empty: tables still exist in it, sub-namespaces remain, or stray files (e.g. .stage or hidden files from failed jobs) sit in the directory.
Common situations: Dropping a namespace without first dropping its tables, leftover temp/staging files from aborted Spark jobs, old metadata sidecar files, or sub-namespaces created but never removed.
Related errors
- Cannot drop namespace %s because it still contains Iceberg t
- Namespace %s is not empty. One or more tables exist.
- Cannot drop namespace %s because it still contains non-Icebe
- %s is not empty: %s
- Namespace %s is not empty. Contains %d child namespace(s).
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/27f6f277368e881d.
Report an issue: GitHub.