apache/beam · error · RuntimeException

KeepFn %s must return a boolean, but returns %s instead.

Error message

KeepFn %s must return a boolean, but returns %s instead.

What it means

JavaFilterTransformProvider compiles the user-supplied KeepFn predicate via StringCompiler and validates its output type. It throws this RuntimeException when the compiled keep function's return type (ignoring nullability) is not Schema.FieldType.BOOLEAN, since a filter predicate must produce a boolean.

Source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/transforms/providers/JavaFilterTransformProvider.java:130

    private final Configuration configuration;

    JavaFilterTransform(Configuration configuration) {
      this.configuration = configuration;
    }

    @Override
    public PCollectionRowTuple expand(PCollectionRowTuple input) {
      Schema inputSchema = input.get(INPUT_ROWS_TAG).getSchema();
      JavaRowUdf keepFn;
      try {
        keepFn = new JavaRowUdf(this.configuration.getKeep(), inputSchema);
      } catch (MalformedURLException
          | ReflectiveOperationException
          | StringCompiler.CompileException exn) {
        throw new RuntimeException(exn);
      }
      if (!keepFn.getOutputType().withNullable(false).equals(Schema.FieldType.BOOLEAN)) {
        throw new RuntimeException(
            String.format(
                "KeepFn %s must return a boolean, but returns %s instead.",
                this.configuration.getKeep(), keepFn.getOutputType()));
      }
      boolean handleErrors = ErrorHandling.hasOutput(configuration.getErrorHandling());
      Schema errorSchema = ErrorHandling.errorSchema(inputSchema);

      PCollectionTuple pcolls =
          input
              .get(INPUT_ROWS_TAG)
              .apply(
                  "Filter",
                  ParDo.of(createDoFn(keepFn, errorSchema, handleErrors))
                      .withOutputTags(filteredValues, TupleTagList.of(errorValues)));
      pcolls.get(filteredValues).setRowSchema(inputSchema);
      pcolls.get(errorValues).setRowSchema(errorSchema);

      PCollectionRowTuple result =

View on GitHub (pinned to 12126d8942)

Solutions

  1. Change the KeepFn/expression so its return type is boolean
  2. Wrap the expression in a comparison producing a boolean (e.g. 'field != null && field > 0')
  3. Inspect keepFn.getOutputType() before expanding to catch the mismatch early

Example fix

// before
StringCompiler expression: "input.getCount()"  // returns long
// after
"input.getCount() > 0"  // returns boolean
Defensive patterns

Strategy: validation

Validate before calling

if (!keepFn.getOutputType().withNullable(false).equals(Schema.FieldType.BOOLEAN))
  throw new IllegalArgumentException("KeepFn must return boolean");

Type guard

boolean returnsBoolean(TypeDescriptor<?> t) { return Schema.FieldType.of(t).withNullable(false).equals(Schema.FieldType.BOOLEAN); }

Try / catch

try { expand(input); } catch (RuntimeException e) { if (e.getMessage().contains("must return a boolean")) { /* fix expression */ } else throw e; }

Prevention

When it happens

Trigger: expand() calls the compiled keepFn and checks getOutputType(); if the user-provided expression/callable returns e.g. String, Long, or Void, the check fails and the RuntimeException is thrown.

Common situations: Writing a filter expression that returns a non-boolean value (e.g. a string comparison result, a numeric value); supplying a callable whose return type is Object or wrapped.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/2cf0b2db8e9b0532. Report an issue: GitHub.