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

  1. Drop all tables in the namespace first (loop over listTables and call dropTable).
  2. Recursively drop sub-namespaces via listNamespaces.
  3. Inspect the directory for stray/non-Iceberg files and remove or relocate them (only if safe).
  4. 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

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


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