apache/flink · error · InvalidProgramException

The iteration {} has no input (initial partial solution).

Error message

The iteration {} has no input (initial partial solution).

What it means

Thrown by CollectionExecutor.executeBulkIteration() when iteration.getInput() returns null. Bulk iterations require an initial partial solution (the seed data for the iteration loop); without it, the iteration has no starting point. This is an InvalidProgramException indicating the iteration was not fully constructed.

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/common/operators/CollectionExecutor.java:325

            for (Map.Entry<String, Operator<?>> bcInputs :
                    operator.getBroadcastInputs().entrySet()) {
                List<?> bcData = execute(bcInputs.getValue(), jobInfo);
                ctx.setBroadcastVariable(bcInputs.getKey(), bcData);
            }
        } else {
            ctx = null;
        }

        return typedOp.executeOnCollections(inputData1, inputData2, ctx, executionConfig);
    }

    @SuppressWarnings("unchecked")
    private <T> List<T> executeBulkIteration(BulkIterationBase<?> iteration, JobInfo jobInfo)
            throws Exception {
        Operator<?> inputOp = iteration.getInput();
        if (inputOp == null) {
            throw new InvalidProgramException(
                    "The iteration "
                            + iteration.getName()
                            + " has no input (initial partial solution).");
        }
        if (iteration.getNextPartialSolution() == null) {
            throw new InvalidProgramException(
                    "The iteration "
                            + iteration.getName()
                            + " has no next partial solution defined (is not closed).");
        }

        List<T> inputData = (List<T>) execute(inputOp, jobInfo);

        // get the operators that are iterative
        Set<Operator<?>> dynamics = new LinkedHashSet<Operator<?>>();
        DynamicPathCollector dynCollector = new DynamicPathCollector(dynamics);
        iteration.getNextPartialSolution().accept(dynCollector);
        if (iteration.getTerminationCriterion() != null) {

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Ensure the initial input DataSet for the iteration is non-null before calling iterate().
  2. Verify the source transformation feeding the iteration (e.g., env.fromCollection()) returns a valid DataSet.
  3. Print the execution plan to confirm the iteration's input is wired.

Example fix

// before — initialDataSet is null
DataSet<Long> initialDataSet = null;
IterativeDataSet<Long> iter = initialDataSet.iterate(100);
// after
DataSet<Long> initialDataSet = env.fromSequence(0, 100);
IterativeDataSet<Long> iter = initialDataSet.iterate(100);
Defensive patterns

Strategy: validation

Validate before calling

// Ensure initial partial solution is non-null
if (initialDataSet == null) {
    throw new IllegalStateException("Initial input for bulk iteration is null");
}
IterativeDataSet<Long> iter = initialDataSet.iterate(100);

Prevention

When it happens

Trigger: A BulkIterationBase operator is created but its initial input (the initial partial solution) was never set. In the high-level API, this happens if the DataSet passed to iterate() is null, or if the iteration operator was built programmatically without calling setInput().

Common situations: A developer creates a bulk iteration but the initial DataSet variable is null because the source read or preceding transformation that should feed it failed or was skipped. Rare in normal API usage since iterate() accepts a DataSet; more common in low-level plan construction.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/2c3e19922d5fa785. Report an issue: GitHub.