apache/iceberg · error · IllegalStateException

Failed to update: %d of %d succeeded

Error message

Failed to update: %d of %d succeeded

What it means

updateProperties() executes JdbcUtil.updatePropertiesStatement expecting one updated row per property. If fewer rows are updated it throws IllegalStateException "Failed to update: %d of %d succeeded" — the UPDATE affected fewer rows than properties supplied, indicating inconsistent catalog rows (e.g., a property row was deleted concurrently).

Source

Thrown at core/src/main/java/org/apache/iceberg/jdbc/JdbcCatalog.java:878

  }

  private boolean updateProperties(Namespace namespace, Map<String, String> properties) {
    String namespaceName = JdbcUtil.namespaceToString(namespace);
    Stream<String> caseArgs =
        properties.entrySet().stream()
            .flatMap(entry -> Stream.of(entry.getKey(), entry.getValue()));
    Stream<String> whereArgs =
        Stream.concat(Stream.of(catalogName, namespaceName), properties.keySet().stream());

    String[] args = Stream.concat(caseArgs, whereArgs).toArray(String[]::new);

    int updatedRecords = execute(JdbcUtil.updatePropertiesStatement(properties.size()), args);

    if (updatedRecords == properties.size()) {
      return true;
    }

    throw new IllegalStateException(
        String.format(
            Locale.ROOT,
            "Failed to update: %d of %d succeeded",
            updatedRecords,
            properties.size()));
  }

  private boolean deleteProperties(Namespace namespace, Set<String> properties) {
    String namespaceName = JdbcUtil.namespaceToString(namespace);
    String[] args =
        Stream.concat(Stream.of(catalogName, namespaceName), properties.stream())
            .toArray(String[]::new);

    return execute(JdbcUtil.deletePropertiesStatement(properties), args) > 0;
  }

  @Override
  protected Map<String, String> properties() {

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Retry setProperties; missing keys may need insertProperties instead of update
  2. Reconcile by reading loadNamespaceMetadata and setting only keys that exist for update
  3. Avoid concurrent writers to the same namespace properties
  4. Check for earlier "Failed to insert" failures leaving partial state and repair those rows

Example fix

// before
catalog.setProperties(ns, props);
// after
Map<String, String> existing = catalog.loadNamespaceMetadata(ns);
if (existing.keySet().containsAll(props.keySet())) {
  catalog.setProperties(ns, props);
} else {
  throw new IllegalStateException("Cannot update missing properties: " + props.keySet());
}
Defensive patterns

Strategy: validation

Validate before calling

Map<String, String> existing = catalog.loadNamespaceMetadata(ns);
if (!existing.keySet().containsAll(props.keySet())) {
  throw new IllegalStateException("Cannot update: some keys missing in catalog");
}
catalog.setProperties(ns, props);

Try / catch

try {
  catalog.setProperties(ns, props);
} catch (IllegalStateException e) {
  if (e.getMessage().startsWith("Failed to update")) {
    LOG.error("Partial property update; re-reading catalog state");
    throw e;
  } else throw e;
}

Prevention

When it happens

Trigger: setProperties where some property keys are missing from the catalog table (deleted concurrently or partially inserted earlier), or the catalog schema's key constraints differ; the UPDATE then matches fewer rows than requested.

Common situations: Race with another client dropping the same namespace properties; recovery from a prior partial insert; databases where update counts don't match row matches (depending on driver settings).

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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