apache/iceberg · error · IllegalArgumentException

Unexpected distribution mode: mode

Error message

Unexpected distribution mode: mode

What it means

copyOnWriteDeleteUpdateDistribution() builds the distribution for copy-on-write DELETE/UPDATE operations. Supported modes are NONE and HASH (with RANGE falling through in some variants); an unrecognized mode throws IllegalArgumentException with 'Unexpected distribution mode'.

Source

Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/SparkWriteUtil.java:131

      case NONE:
        return Distributions.unspecified();

      case HASH:
        if (table.spec().isPartitioned()) {
          return Distributions.clustered(clustering(table));
        } else {
          return Distributions.clustered(FILE_CLUSTERING);
        }

      case RANGE:
        if (table.spec().isPartitioned() || table.sortOrder().isSorted()) {
          return Distributions.ordered(ordering(table));
        } else {
          return Distributions.ordered(EXISTING_ROW_ORDERING);
        }

      default:
        throw new IllegalArgumentException("Unexpected distribution mode: " + mode);
    }
  }

  /** Builds requirements for merge-on-read DELETE, UPDATE, MERGE operations. */
  public static SparkWriteRequirements positionDeltaRequirements(
      Table table,
      Command command,
      DistributionMode mode,
      boolean fanoutEnabled,
      long advisoryPartitionSize) {

    if (command == UPDATE || command == MERGE) {
      Distribution distribution = positionDeltaUpdateMergeDistribution(table, mode);
      SortOrder[] ordering = positionDeltaUpdateMergeOrdering(table, fanoutEnabled);
      return new SparkWriteRequirements(distribution, ordering, advisoryPartitionSize);
    } else {
      Distribution distribution = positionDeltaDeleteDistribution(table, mode);
      SortOrder[] ordering = fanoutEnabled ? EMPTY_ORDERING : POSITION_DELETE_ORDERING;

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Change the delete/update distribution-mode override to a supported value (none or hash)
  2. Remove the operation-specific override so it falls back to the table-level supported mode
  3. Upgrade the Iceberg Spark module for broader mode support

Example fix

// before
spark.conf.set("write.delete.distribution-mode", "range")
// after
spark.conf.set("write.delete.distribution-mode", "hash")
Defensive patterns

Strategy: validation

Validate before calling

if (mode != DistributionMode.NONE && mode != DistributionMode.HASH) {
  throw new IllegalArgumentException("CoW delete/update supports only none/hash, got " + mode);
}

Type guard

boolean coWDeleteUpdateSupported = mode == DistributionMode.NONE || mode == DistributionMode.HASH;

Try / catch

try {
  dist = SparkWriteUtil.copyOnWriteDeleteUpdateDistribution(table, mode, ...);
} catch (IllegalArgumentException e) {
  dist = SparkWriteUtil.copyOnWriteDeleteUpdateDistribution(table, DistributionMode.HASH, ...);
}

Prevention

When it happens

Trigger: Invoking this via SparkWriteUtil.distribution() for a CoW DELETE/UPDATE when the resolved DistributionMode is not in the handled set (e.g. RANGE where only NONE/HASH are handled here, or an unknown enum constant).

Common situations: Configuration like write.delete.distribution-mode=range on a Spark version where CoW delete/update only supports none/hash; custom write requirements passing an unexpected mode.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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