apache/iceberg · error · RuntimeException

Cannot create namespace '%s': %s

Error message

Cannot create namespace '%s': %s

What it means

This is the catch-all in NessieIcebergClient.createNamespace: any NessieConflictException that isn't KEY_EXISTS or NAMESPACE_ABSENT (or other unhandled commit conflicts) is wrapped in a RuntimeException formatted as 'Cannot create namespace %s: <conflict message>'. It surfaces server-side conflict details without a typed Iceberg exception.

Source

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

        Optional<Conflict> conflict =
            NessieUtil.extractSingleConflict(
                e,
                EnumSet.of(
                    Conflict.ConflictType.KEY_EXISTS, Conflict.ConflictType.NAMESPACE_ABSENT));
        if (conflict.isPresent()) {
          switch (conflict.get().conflictType()) {
            case KEY_EXISTS:
              Content conflicting = withReference(api.getContent()).key(key).get().get(key);
              throw namespaceAlreadyExists(key, conflicting, e);
            case NAMESPACE_ABSENT:
              throw new NoSuchNamespaceException(
                  e,
                  "Cannot create namespace '%s': parent namespace '%s' does not exist",
                  namespace,
                  conflict.get().key());
          }
        }
        throw new RuntimeException(
            String.format("Cannot create namespace '%s': %s", namespace, e.getMessage()));
      }
    } catch (NessieNotFoundException e) {
      throw new UncheckedIOException(
          String.format(
              "Cannot create namespace '%s': ref '%s' is no longer valid.",
              namespace, getRef().getName()),
          e);
    } catch (BaseNessieClientServerException e) {
      throw new UncheckedIOException(
          String.format("Cannot create namespace '%s': %s", namespace, e.getMessage()), e);
    }
  }

  public List<Namespace> listNamespaces(Namespace namespace) throws NoSuchNamespaceException {
    try {
      String filter = "entry.contentType == 'NAMESPACE' && ";
      if (namespace.isEmpty()) {

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Retry the createNamespace after refreshing the catalog/client so it commits against the latest ref hash.
  2. Serialize namespace creation (avoid multiple processes creating the same namespace concurrently), or tolerate a RuntimeException as 'someone else created it' and verify with namespaceExists.
  3. Inspect the wrapped message for the underlying Nessie conflict and fix per its cause (e.g. switch to the correct branch).

Example fix

// before
catalog.createNamespace(ns); // RuntimeException on conflict
// after
try {
  catalog.createNamespace(ns);
} catch (RuntimeException e) {
  if (catalog.namespaceExists(ns)) {
    // created concurrently; proceed
  } else {
    throw e;
  }
}
Defensive patterns

Strategy: retry

Validate before calling

// minimize conflict windows: refresh ref state before committing
api.reference().refName(branch).get(); // confirm current hash before createNamespace

Try / catch

try {
  catalog.createNamespace(ns);
} catch (RuntimeException e) {
  if (catalog.namespaceExists(ns)) {
    // concurrent creation; treat as success
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling createNamespace while the Nessie server reports an unexpected conflict type — e.g. concurrent commits to the same branch producing a generic Conflict, ref hash changed (update on stale ref), or server-side validation errors other than KEY_EXISTS/NAMESPACE_ABSENT.

Common situations: Concurrent writers committing namespaces/tables to the same branch simultaneously; branch was force-updated between client reads and the commit; using a detached/tag ref that disallows the operation.

Related errors


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