apache/iceberg · error · UncheckedIOException

Cannot drop namespace '%s': %s

Error message

Cannot drop namespace '%s': %s

What it means

Fallback handler in dropNamespace: when a NessieReferenceConflictException carries an unrecognized conflict (or multiple/unextractable conflicts), it is rethrown as UncheckedIOException 'Cannot drop namespace X: <server message>'. The server rejected the delete commit for a reason the client does not specially classify.

Source

Thrown at nessie/src/main/java/org/apache/iceberg/nessie/NessieIcebergClient.java:352

        commitRetry("drop namespace " + key, Operation.Delete.of(key));
        return true;
      } catch (NessieReferenceConflictException e) {
        Optional<Conflict> conflict =
            NessieUtil.extractSingleConflict(
                e,
                EnumSet.of(
                    Conflict.ConflictType.KEY_DOES_NOT_EXIST,
                    Conflict.ConflictType.NAMESPACE_NOT_EMPTY));
        if (conflict.isPresent()) {
          Conflict.ConflictType conflictType = conflict.get().conflictType();
          switch (conflictType) {
            case KEY_DOES_NOT_EXIST:
              return false;
            case NAMESPACE_NOT_EMPTY:
              throw new NamespaceNotEmptyException(e, "Namespace '%s' is not empty.", namespace);
          }
        }
        throw new UncheckedIOException(
            String.format("Cannot drop namespace '%s': %s", namespace, e.getMessage()), e);
      }
    } catch (NessieNotFoundException e) {
      LOG.error(
          "Cannot drop namespace '{}': ref '{}' is no longer valid.",
          namespace,
          getRef().getName(),
          e);
    } catch (BaseNessieClientServerException e) {
      throw new UncheckedIOException(
          String.format("Cannot drop namespace '%s': %s", namespace, e.getMessage()), e);
    }
    return false;
  }

  private static void checkNamespaceIsValid(Namespace namespace) {
    if (namespace.isEmpty()) {
      throw new NoSuchNamespaceException("Invalid namespace: %s", namespace);

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Inspect the wrapped cause (NessieReferenceConflictException) and server message for the actual conflict.
  2. Retry the drop after concurrent operations on the ref settle.
  3. Upgrade iceberg-nessie to a client version matching your Nessie server.
  4. Update ref contents via the Nessie API directly if the conflict needs manual resolution.

Example fix

// before
catalog.dropNamespace(ns); // UncheckedIOException on unknown conflict
// after
try {
  catalog.dropNamespace(ns);
} catch (UncheckedIOException e) {
  LOG.warn("drop conflict: {}", e.getCause(), e);
  // re-inspect ref state, then retry
}
Defensive patterns

Strategy: retry

Validate before calling

// minimize race window: re-read ref state immediately before drop
Content c = api.getContent().reference(ref).key(key).get().get(key);

Try / catch

try {
  return catalog.dropNamespace(ns);
} catch (UncheckedIOException e) {
  if (e.getCause() instanceof NessieReferenceConflictException && attempt < 3) {
    return dropNamespaceWithRetry(ns, attempt + 1); // bounded retry after conflict
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling dropNamespace when the server returns a conflict type other than KEY_DOES_NOT_EXIST or NAMESPACE_NOT_EMPTY (e.g. unexpected concurrent mutation, server-side validation conflicts).

Common situations: Heavy concurrent commits on the same ref; Nessie server version emitting new conflict types unknown to the client.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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