apache/flink · error · InvalidProgramException
The binary operation {} has no second input.
Error message
The binary operation {} has no second input. What it means
Thrown by CollectionExecutor.executeBinaryOperator() when operator.getSecondInput() returns null for a DualInputOperator (e.g., JoinOperator, CoGroupOperator). This is the symmetric counterpart of error 367: the right (second) input is null. A binary operator needs both inputs to produce results.
Source
Thrown at flink-core/src/main/java/org/apache/flink/api/common/operators/CollectionExecutor.java:287
} 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
TaskInfo taskInfo = new TaskInfoImpl(typedOp.getName(), 1, 0, 1, 0);
RuntimeUDFContext ctx;
if (RichFunction.class.isAssignableFrom(typedOp.getUserCodeWrapper().getUserCodeClass())) {View on GitHub (pinned to 2f3c205e92)
Solutions
- Verify the right input DataSet is non-null before the join/cogroup/cross call.
- Print the plan or check both input variables in a debugger to identify which side is null.
- Ensure both source readers (readTextFile, fromCollection, etc.) return non-null DataSets.
Example fix
// before — rightInput is null DataSet<Tuple2> rightInput = null; leftInput.join(rightInput).where(0).equalTo(0); // after DataSet<Tuple2> rightInput = env.fromElements(Tuple2.of(1, "x")); leftInput.join(rightInput).where(0).equalTo(0);
Defensive patterns
Strategy: validation
Validate before calling
// Verify right input is non-null before join/cogroup/cross
if (rightInput == null) {
throw new IllegalStateException("Right input for join is null");
}
leftInput.join(rightInput).where(0).equalTo(0); Prevention
- Validate both join inputs are non-null — check the right side specifically.
- Ensure source readers producing join inputs return non-null DataSets.
- Print the plan to verify the second input of each DualInputOperator is connected.
When it happens
Trigger: A DualInputOperator is created where the right input DataSet is null. In the high-level API, the DataSet on the right side of a .join()/.cogroup()/.cross() call is null. For example, leftInput.join(nullRhs) or the right DataSet variable was never assigned.
Common situations: The right-side DataSet of a join/cogroup/cross is null because the transformation producing it was skipped, returned null, or the variable was conditionally assigned. Frequently seen when join inputs come from different source reads and one source fails to initialize.
Related errors
- The binary operation {} has no first input.
- The data sink {} has no input.
- The unary operation {} has no input.
- The iteration {} has no input (initial partial solution).
- The delta iteration {} has no initial solution set.
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/68ec541077ea4248.
Report an issue: GitHub.