prestodb/presto · error · IllegalArgumentException

non-native (java) execution requires only one scheduledSplit

Error message

non-native (java) execution requires only one scheduledSplits but [%d] were found [%s]

What it means

In Java (non-native) execution, each Spark task's driver is created with exactly one scheduled split; PrestoSparkTaskExecution.createDriver enforces this and throws IllegalArgumentException when more than one split is supplied. This is an internal invariant: the Java driver assumes a single split per task.

Source

Thrown at presto-spark-base/src/main/java/com/facebook/presto/spark/execution/task/PrestoSparkTaskExecution.java:368

            this.pipelineContext = taskContext.addPipelineContext(driverFactory.getPipelineId(), driverFactory.isInputDriver(), driverFactory.isOutputDriver(), partitioned);
        }

        public DriverSplitRunner createDriverRunner(@Nullable List<ScheduledSplit> scheduledSplits)
        {
            checkState(!noMoreDriverRunner.get(), "Cannot create driver for pipeline: %s", pipelineContext.getPipelineId());
            pendingCreation.incrementAndGet();
            // create driver context immediately so the driver existence is recorded in the stats
            // splitWeight can be 0 as we don't load balance the executor based on their load average
            DriverContext driverContext = pipelineContext.addDriverContext(0, Lifespan.taskWide(), driverFactory.getFragmentResultCacheContext());
            return new DriverSplitRunner(this, driverContext, scheduledSplits);
        }

        public Driver createDriver(DriverContext driverContext, @Nullable List<ScheduledSplit> scheduledSplits)
        {
            Driver driver = driverFactory.createDriver(driverContext);
            if (scheduledSplits != null && scheduledSplits.size() > 0) {
                if (!nativeExecution && scheduledSplits.size() != 1) {
                    throw new IllegalArgumentException(format("non-native (java) execution requires only one scheduledSplits but [%d] were found [%s]",
                            scheduledSplits.size(),
                            Joiner.on(",").join(scheduledSplits.stream().map(ScheduledSplit::toString).collect(Collectors.toList()))));
                }
                PlanNodeId sourceNodeId = nativeExecution ? driver.getSourceId().get() : Iterables.getOnlyElement(scheduledSplits).getPlanNodeId();
                // TableScanOperator requires partitioned split to be added before the first call to process
                driver.updateSource(new TaskSource(sourceNodeId, ImmutableSet.copyOf(scheduledSplits), true));
            }

            verify(pendingCreation.get() > 0, "pendingCreation is expected to be greater than zero");
            pendingCreation.decrementAndGet();

            closeDriverFactoryIfFullyCreated();

            return driver;
        }

        public void noMoreDriverRunner()
        {

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Verify each Java-execution task input maps exactly one scheduled split per driver; inspect PrestoSparkTaskInputs construction
  2. Ensure you are not accidentally routing native-style multi-split inputs to the Java executor (check nativeExecution flag consistency)
  3. Upgrade Presto on Spark version — internal split assignment logic may have been fixed
  4. If you supply custom task inputs, fix your partitioning logic to emit one split per task

Example fix

// before (custom input builder)
taskInputs.add(split1);
taskInputs.add(split2);
// after
checkState(splits.size() == 1, "java execution supports exactly one split per task");
taskInputs.add(Iterables.getOnlyElement(splits));
Defensive patterns

Strategy: validation

Validate before calling

if (!nativeExecution && scheduledSplits != null && scheduledSplits.size() > 1) {
    throw new IllegalArgumentException("java execution requires exactly one split, got " + scheduledSplits.size());
}

Type guard

boolean hasSingleSplit(List<ScheduledSplit> splits) { return splits == null || splits.size() <= 1; }

Try / catch

try { driver = createDriver(ctx, splits); } catch (IllegalArgumentException e) { if (e.getMessage().contains("only one scheduledSplits")) { log.error("multi-split input for java driver", e); } throw e; }

Prevention

When it happens

Trigger: createDriver is invoked with a scheduledSplits list of size > 1 while nativeExecution is false (a Spark task receives multiple scheduled splits in PrestoSparkTaskInputs for a non-native execution).

Common situations: Bugs or custom modifications in PrestoSparkInput partitioning logic that assign multiple splits to a single task; corrupted or hand-crafted RDD inputs; version mismatches between coordinator task planning and Spark executor inputs.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/3d7b50563160dcff. Report an issue: GitHub.