apache/flink · error · IllegalArgumentException

The number of iterations must be at least one.

Error message

The number of iterations must be at least one.

What it means

Thrown by BulkIterationBase.setMaximumNumberOfIterations(int num) when num is less than 1. A bulk iteration must run at least one iteration; zero or negative iteration counts are nonsensical and indicate a configuration error.

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/common/operators/base/BulkIterationBase.java:149

                        new TerminationCriterionMapper<X>(),
                        new UnaryOperatorInformation<X, X>(type, type),
                        "Termination Criterion Aggregation Wrapper");
        mapper.setInput(criterion);

        this.terminationCriterion = mapper;
        this.getAggregators()
                .registerAggregationConvergenceCriterion(
                        TERMINATION_CRITERION_AGGREGATOR_NAME,
                        new TerminationCriterionAggregator(),
                        new TerminationCriterionAggregationConvergence());
    }

    /**
     * @param num
     */
    public void setMaximumNumberOfIterations(int num) {
        if (num < 1) {
            throw new IllegalArgumentException("The number of iterations must be at least one.");
        }
        this.numberOfIterations = num;
    }

    public int getMaximumNumberOfIterations() {
        return this.numberOfIterations;
    }

    @Override
    public AggregatorRegistry getAggregators() {
        return this.aggregators;
    }

    /**
     * @throws InvalidProgramException
     */
    public void validate() throws InvalidProgramException {
        if (this.input == null) {

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Validate the iteration count is >= 1 before calling setMaximumNumberOfIterations; clamp or fail early.
  2. Use Math.max(1, num) to guarantee a minimum of one iteration when the value comes from external config.
  3. If the iteration count is genuinely zero (no work to do), skip creating the iteration entirely.
  4. Alternatively, use a termination criterion (setTerminationCriterion) instead of a fixed count when the number of iterations is uncertain.

Example fix

// before
int maxIters = getConfiguredIterations(); // could be 0
iteration.setMaximumNumberOfIterations(maxIters); // throws if < 1

// after
int maxIters = Math.max(1, getConfiguredIterations());
iteration.setMaximumNumberOfIterations(maxIters);
Defensive patterns

Strategy: validation

Validate before calling

void safeSetMaxIterations(BulkIterationBase<?> iter, int num) {
    if (num < 1) {
        throw new IllegalArgumentException("Iteration count must be >= 1, got: " + num);
    }
    iter.setMaximumNumberOfIterations(num);
}

Type guard

boolean isValidIterationCount(int num) {
    return num >= 1;
}

Try / catch

try {
    iteration.setMaximumNumberOfIterations(computedCount);
} catch (IllegalArgumentException e) {
    // count was < 1; clamp or fail
    iteration.setMaximumNumberOfIterations(Math.max(1, computedCount));
}

Prevention

When it happens

Trigger: Calling iteration.setMaximumNumberOfIterations(0) or with a negative value. Passing a computed iteration count that could be zero or negative due to upstream logic.

Common situations: Dynamically computing the number of iterations from data or config (e.g., Math.max(0, someValue)) without clamping to at least 1. Passing a user-provided configuration value that was not validated. Integer underflow or off-by-one in iteration count calculation.

Related errors


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