apache/flink · error · InvalidProgramException

The binary operation {} has no first input.

Error message

The binary operation {} has no first input.

What it means

Thrown by CollectionExecutor.executeBinaryOperator() when operator.getFirstInput() returns null for a DualInputOperator (e.g., JoinOperator, CoGroupOperator, CrossOperator). Binary operators require two inputs; if the first (left) input is null, the operator cannot execute. This is an InvalidProgramException indicating an incomplete join/cogroup/cross plan.

Source

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

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

        return typedOp.executeOnCollections(inputData, ctx, executionConfig);
    }

    private <IN1, IN2, OUT> List<OUT> executeBinaryOperator(
            DualInputOperator<?, ?, ?, ?> operator, int superStep, JobInfo jobInfo)
            throws Exception {
        Operator<?> inputOp1 = operator.getFirstInput();
        Operator<?> inputOp2 = operator.getSecondInput();

        if (inputOp1 == null) {
            throw new InvalidProgramException(
                    "The binary operation " + operator.getName() + " has no first input.");
        }
        if (inputOp2 == null) {
            throw new InvalidProgramException(
                    "The binary operation " + operator.getName() + " has no second input.");
        }

        // compute inputs
        @SuppressWarnings("unchecked")
        List<IN1> inputData1 = (List<IN1>) execute(inputOp1, superStep, jobInfo);
        @SuppressWarnings("unchecked")
        List<IN2> inputData2 = (List<IN2>) execute(inputOp2, superStep, jobInfo);

        @SuppressWarnings("unchecked")
        DualInputOperator<IN1, IN2, OUT, ?> typedOp =
                (DualInputOperator<IN1, IN2, OUT, ?>) operator;

        // build the runtime context and compute broadcast variables, if necessary

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Verify the left input DataSet is non-null before calling .join()/.cogroup()/.cross().
  2. Inspect the execution plan (env.createPlanAsJSON()) to confirm the first input of each binary operator is wired.
  3. Trace the left input variable's assignment path for null-returning transformations or missed assignments.

Example fix

// before — leftInput is null
DataSet<Tuple2> leftInput = null;
leftInput.join(rightInput).where(0).equalTo(0);
// after
DataSet<Tuple2> leftInput = env.fromElements(Tuple2.of(1, "a"));
leftInput.join(rightInput).where(0).equalTo(0);
Defensive patterns

Strategy: validation

Validate before calling

// Verify left input is non-null before join/cogroup/cross
if (leftInput == null) {
    throw new IllegalStateException("Left input for join is null");
}
leftInput.join(rightInput).where(0).equalTo(0);

Prevention

When it happens

Trigger: A DualInputOperator (join, cogroup, cross, etc.) is created where the left input DataSet is null. In the high-level API this occurs when the first argument to .join()/.cogroup()/.crossWithHuge() is null or was never set.

Common situations: A left-input DataSet variable is null due to an upstream assignment bug, conditional logic that skipped the assignment, or a transformation that unexpectedly returned null. Common in complex pipelines where join inputs are computed conditionally.

Related errors


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