apache/iceberg · error · UncheckedIOException

Cannot update properties on namespace '%s': %s

Error message

Cannot update properties on namespace '%s': %s

What it means

updateProperties commits a namespace-objects Put via commitRetry; when the commit fails with NessieReferenceConflictException that is NOT the benign KEY_DOES_NOT_EXIST conflict, the client wraps it in an UncheckedIOException 'Cannot update properties on namespace ... : <server message>'. This signals a merge-style conflict on the ref (content changed concurrently) that Iceberg surfaces as a generic IO failure.

Source

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

            action.accept(newProperties);
            org.projectnessie.model.Namespace updatedNamespace =
                org.projectnessie.model.Namespace.builder()
                    .from(oldNamespace)
                    .properties(newProperties)
                    .build();
            commitBuilder.operation(Operation.Put.of(key, updatedNamespace));
            return commitBuilder;
          });
      // always successful, otherwise an exception is thrown
      return true;
    } catch (NessieReferenceConflictException e) {
      Optional<Conflict> conflict =
          NessieUtil.extractSingleConflict(e, EnumSet.of(Conflict.ConflictType.KEY_DOES_NOT_EXIST));
      if (conflict.isPresent()
          && conflict.get().conflictType() == Conflict.ConflictType.KEY_DOES_NOT_EXIST) {
        throw new NoSuchNamespaceException(e, "Namespace does not exist: %s", namespace);
      }
      throw new UncheckedIOException(
          String.format(
              "Cannot update properties on namespace '%s': %s", namespace, e.getMessage()),
          e);
    } catch (NessieContentNotFoundException e) {
      throw new NoSuchNamespaceException("Namespace does not exist: %s", namespace);
    } catch (NessieReferenceNotFoundException e) {
      throw new UncheckedIOException(
          String.format(
              "Cannot update properties on namespace '%s': ref '%s' is no longer valid.",
              namespace, getRef().getName()),
          e);
    } catch (BaseNessieClientServerException e) {
      throw new UncheckedIOException(
          String.format("Cannot update namespace '%s': %s", namespace, e.getMessage()), e);
    }
  }

  public void renameTable(TableIdentifier from, TableIdentifier to) {

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Retry the setProperties/removeProperties call — updateProperties already retries via commitRetry, but persistent conflicts require re-running after the other writer finishes.
  2. Serialize namespace property updates through a single writer or use a mutable branch dedicated to metadata changes.
  3. Inspect the embedded server conflict message (e.getMessage()) to identify the conflicting key and coordinate with the other writer.
  4. If conflicts are frequent, switch the workload to write to per-job branches and merge deliberately.

Example fix

// before
catalog.setProperties(ns, props); // UncheckedIOException on concurrent conflict
// after
try {
  catalog.setProperties(ns, props);
} catch (UncheckedIOException e) {
  // transient concurrent-modification conflict; back off and retry
  Thread.sleep(1000);
  catalog.setProperties(ns, props);
}
Defensive patterns

Strategy: retry

Validate before calling

boolean busy = recentWritersOn(namespace); // your own coordination/lock mechanism
if (busy) { waitUntilFree(namespace); }

Try / catch

int attempts = 3;
while (attempts-- > 0) {
  try { catalog.setProperties(ns, props); break; }
  catch (UncheckedIOException e) {
    if (attempts == 0 || !isConflictMessage(e)) throw e;
    sleep(backoff);
  }
}

Prevention

When it happens

Trigger: setProperties/removeProperties where another commit concurrently modified the same namespace key (or another conflicting key) on the branch, producing a reference conflict other than KEY_DOES_NOT_EXIST; the conflict cannot be attributed to a missing namespace.

Common situations: Two writers updating the same namespace properties simultaneously; a rebase/merge on the Nessie branch introducing conflicts; namespace object changed by a different tool (e.g. Spark vs Flink jobs) between read and commit.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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