{"record":{"id":"2cf0b2db8e9b0532","repo":"apache/beam","slug":"keepfn-s-must-return-a-boolean-but-returns-s-instead","errorCode":null,"errorMessage":"KeepFn %s must return a boolean, but returns %s instead.","messagePattern":"KeepFn (.+?) must return a boolean, but returns (.+?) instead\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/transforms/providers/JavaFilterTransformProvider.java","lineNumber":130,"sourceCode":"    private final Configuration configuration;\n\n    JavaFilterTransform(Configuration configuration) {\n      this.configuration = configuration;\n    }\n\n    @Override\n    public PCollectionRowTuple expand(PCollectionRowTuple input) {\n      Schema inputSchema = input.get(INPUT_ROWS_TAG).getSchema();\n      JavaRowUdf keepFn;\n      try {\n        keepFn = new JavaRowUdf(this.configuration.getKeep(), inputSchema);\n      } catch (MalformedURLException\n          | ReflectiveOperationException\n          | StringCompiler.CompileException exn) {\n        throw new RuntimeException(exn);\n      }\n      if (!keepFn.getOutputType().withNullable(false).equals(Schema.FieldType.BOOLEAN)) {\n        throw new RuntimeException(\n            String.format(\n                \"KeepFn %s must return a boolean, but returns %s instead.\",\n                this.configuration.getKeep(), keepFn.getOutputType()));\n      }\n      boolean handleErrors = ErrorHandling.hasOutput(configuration.getErrorHandling());\n      Schema errorSchema = ErrorHandling.errorSchema(inputSchema);\n\n      PCollectionTuple pcolls =\n          input\n              .get(INPUT_ROWS_TAG)\n              .apply(\n                  \"Filter\",\n                  ParDo.of(createDoFn(keepFn, errorSchema, handleErrors))\n                      .withOutputTags(filteredValues, TupleTagList.of(errorValues)));\n      pcolls.get(filteredValues).setRowSchema(inputSchema);\n      pcolls.get(errorValues).setRowSchema(errorSchema);\n\n      PCollectionRowTuple result =","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/transforms/providers/JavaFilterTransformProvider.java#L112-L148","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Change the KeepFn/expression so its return type is boolean","Wrap the expression in a comparison producing a boolean (e.g. 'field != null && field > 0')","Inspect keepFn.getOutputType() before expanding to catch the mismatch early"],"exampleFix":"// before\nStringCompiler expression: \"input.getCount()\"  // returns long\n// after\n\"input.getCount() > 0\"  // returns boolean","handlingStrategy":"validation","validationCode":"if (!keepFn.getOutputType().withNullable(false).equals(Schema.FieldType.BOOLEAN))\n  throw new IllegalArgumentException(\"KeepFn must return boolean\");","typeGuard":"boolean returnsBoolean(TypeDescriptor<?> t) { return Schema.FieldType.of(t).withNullable(false).equals(Schema.FieldType.BOOLEAN); }","tryCatchPattern":"try { expand(input); } catch (RuntimeException e) { if (e.getMessage().contains(\"must return a boolean\")) { /* fix expression */ } else throw e; }","preventionTips":["Write filter expressions that end in a boolean comparison","Type-check keepFn output before running the pipeline"],"tags":["java","apache-beam","filter","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}