apache/iceberg · error · IllegalArgumentException

Unknown planning mode: ${mode}

Error message

Unknown planning mode: ${mode}

What it means

shouldPlanLocally() switches on a configured planning mode (enum of AUTO and remote/local preferences); an unrecognized mode reaches the default branch and throws IllegalArgumentException('Unknown planning mode'). This indicates the stored mode value is not a valid PlanningMode, typically from an invalid property value or a version mismatch where an older core sees a newer mode name.

Source

Thrown at core/src/main/java/org/apache/iceberg/BaseDistributedDataScan.java:256

  private boolean shouldPlanLocally(PlanningMode mode, List<ManifestFile> manifests) {
    if (context().planWithCustomizedExecutor()) {
      return true;
    }

    switch (mode) {
      case LOCAL:
        return true;

      case DISTRIBUTED:
        return manifests.isEmpty();

      case AUTO:
        return remoteParallelism() <= localParallelism
            || manifests.size() <= 2 * localParallelism
            || totalSize(manifests) <= localPlanningSizeThreshold;

      default:
        throw new IllegalArgumentException("Unknown planning mode: " + mode);
    }
  }

  private long totalSize(List<ManifestFile> manifests) {
    return manifests.stream().mapToLong(ManifestFile::length).sum();
  }

  private boolean shouldCopyDataFiles(boolean planDataLocally, boolean loadColumnStats) {
    return planDataLocally
        || shouldCopyRemotelyPlannedDataFiles()
        || (loadColumnStats && !shouldReturnColumnStats());
  }

  @SuppressWarnings("unchecked")
  private CloseableIterable<ScanTask> planFileTasksLocally(
      List<ManifestFile> dataManifests, List<ManifestFile> deleteManifests) {
    LOG.info("Planning file tasks locally for table {}", table().name());
    ManifestGroup manifestGroup = newManifestGroup(dataManifests, deleteManifests);

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Set the planning mode property to one of the valid enum values (auto, and the defined remote/local modes)
  2. Check for Iceberg version mismatch between the writer of the config and the reader
  3. Use the enum constant programmatically instead of a raw string where possible
  4. Validate configuration values at startup before launching scans

Example fix

// before
String mode = conf.get("iceberg.distributed.plan-mode"); // e.g. "automatic"
// after
String mode = conf.get("iceberg.distributed.plan-mode", "auto"); // must be a valid PlanningMode name
Preconditions.checkArgument(mode.equals("auto") || mode.equals("local") || mode.equals("remote"),
    "Invalid planning mode: %s", mode);
Defensive patterns

Strategy: validation

Validate before calling

String mode = props.get("plan-mode");
Set<String> valid = Set.of("auto", "local", "remote"); // adjust to actual enum names
if (mode != null && !valid.contains(mode)) {
  throw new IllegalArgumentException("Invalid planning mode: " + mode);
}

Type guard

null

Try / catch

try { planFiles(); } catch (IllegalArgumentException e) { /* fix plan-mode config */ }

Prevention

When it happens

Trigger: Setting the distributed-scan planning mode property to a value outside the enum, or deserializing a mode saved by a newer Iceberg version.

Common situations: Typo in configuration property value (e.g. 'autto', 'remote-paralell'); config from a different Iceberg version; programmatic construction with a null/foreign mode object.

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/18f75d9b3bf96c9d. Report an issue: GitHub.