apache/iceberg · error · RuntimeIOException

Namespace delete failed

Error message

Namespace delete failed: %s

What it means

HadoopCatalog.dropNamespace deletes a namespace directory from the warehouse location. If the underlying FileSystem.delete call throws an IOException for any reason other than a non-empty namespace, it is wrapped in this RuntimeIOException carrying the namespace name. The delete is non-recursive, so a partially-populated directory will fail loudly rather than cascade.

Solutions

  1. Check the cause exception (getCause()) to see the underlying FileSystem error and fix it (permissions, cluster availability, safe mode).
  2. Re-check whether the namespace still exists before retrying; a concurrent delete may have already removed it.
  3. Verify the caller has write/delete permission on the namespace directory and its parent.
  4. Retry after the HDFS cluster / object store is healthy, since empty directories can also trip the NamespaceNotEmptyException path.
  5. If namespaces frequently race with other writers, serialize namespace administration operations externally.

Example fix

// before
catalog.dropNamespace(Namespace.of("reports"));
// after
try {
  catalog.dropNamespace(Namespace.of("reports"));
} catch (RuntimeIOException e) {
  LOG.warn("Namespace delete failed for reports: {}", e.getCause());
  // inspect cause: permissions, safe mode, concurrent delete
}
Defensive patterns

Strategy: try-catch

Validate before calling

Namespace ns = Namespace.of("db");
Map<String,String> meta = catalog.loadNamespaceMetadata(ns); // throws NoSuchNamespaceException if missing
// confirm emptiness implicitly: dropNamespace throws NamespaceNotEmptyException if tables exist

Type guard

boolean canDrop = catalog.namespaceExists(ns) && catalog.loadNamespaceMetadata(ns) != null;

Try / catch

try {
  catalog.dropNamespace(ns);
} catch (NamespaceNotEmptyException e) {
  // drop tables first
} catch (RuntimeIOException e) {
  Throwable cause = e.getCause(); // decide: permissions / concurrency / availability
}

Prevention

When it happens

Trigger: Calling catalog.dropNamespace(Namespace) when fs.delete(nsPath, false) throws IOException — e.g. permission denied, the path was concurrently removed by another process, HDFS name-node unavailable, or a stale file handle.

Common situations: Distributed clusters where another job deletes the namespace path between the emptiness check and the delete; HDFS Safe Mode leaving the namespace in read-only state; misconfigured fs permissions on the warehouse location; network partitions to HDFS/S3.

Related errors


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

Appendix: source

Thrown at core/src/main/java/org/apache/iceberg/hadoop/HadoopCatalog.java:350

    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");
  }

  @Override
  public Map<String, String> loadNamespaceMetadata(Namespace namespace) {
    Path nsPath = new Path(warehouseLocation, SLASH.join(namespace.levels()));

View on GitHub (pinned to 86d9c8fc54)