apache/beam · error · IllegalArgumentException

Unknown 'runner' specified '%s', supported pipeline runners

Error message

Unknown 'runner' specified '%s', supported pipeline runners %s

What it means

The 'runner' option value could not be loaded: Class.forName threw ClassNotFoundException, so Beam wraps it in an IllegalArgumentException listing the supported registered runners. This means the runner is neither a registered short name nor a class present on the classpath.

Source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/options/PipelineOptionsFactory.java:1936

          if (pipelineRunners.containsKey(runner.toLowerCase())) {
            convertedOptions.put("runner", pipelineRunners.get(runner.toLowerCase(ROOT)));
          } else {
            try {
              Class<?> runnerClass = Class.forName(runner, true, ReflectHelpers.findClassLoader());
              if (!PipelineRunner.class.isAssignableFrom(runnerClass)) {
                throw new IllegalArgumentException(
                    String.format(
                        "Class '%s' does not implement PipelineRunner. "
                            + "Supported pipeline runners %s",
                        runner, cache.getSupportedRunners()));
              }
              convertedOptions.put("runner", runnerClass);
            } catch (ClassNotFoundException e) {
              String msg =
                  String.format(
                      "Unknown 'runner' specified '%s', supported pipeline runners %s",
                      runner, cache.getSupportedRunners());
              throw new IllegalArgumentException(msg, e);
            }
          }
        } else if (isCollectionOrArrayOfAllowedTypes(returnType, type)) {
          // Split any strings with ","
          List<String> values =
              entry.getValue().stream()
                  .flatMap(input -> Arrays.stream(input.split(",")))
                  .collect(Collectors.toList());

          if (values.contains("")) {
            checkEmptyStringAllowed(returnType, type, method.getGenericReturnType().toString());
          }
          convertedOptions.put(entry.getKey(), MAPPER.convertValue(values, type));
        } else if (isSimpleType(returnType, type)) {
          String value = Iterables.getOnlyElement(entry.getValue());
          if (value.isEmpty()) {
            checkEmptyStringAllowed(returnType, type, method.getGenericReturnType().toString());
          }

View on GitHub (pinned to 12126d8942)

Solutions

  1. Add the runner's dependency artifact to the classpath (e.g., beam-runners-direct-java, beam-runners-google-cloud-dataflow-java)
  2. Use a registered short runner name like DirectRunner or DataflowRunner
  3. Check the supported runners listed in the error and pick one that your dependencies provide

Example fix

// before
--runner=FlinkRunner   // flink runner jar not on classpath
// after
dependencies { runtimeOnly "org.apache.beam:beam-runners-flink-1.17:2.x.x" }
// or use: --runner=DirectRunner
Defensive patterns

Strategy: fallback

Validate before calling

try { Class.forName(runnerClass, true, cl); } catch (ClassNotFoundException e) { /* use default runner */ }

Try / catch

try { PipelineOptionsFactory.fromArgs("--runner=" + runner).create(); } catch (IllegalArgumentException e) { options.setRunner(DirectRunner.class); }

Prevention

When it happens

Trigger: Passing --runner=SomeRunner where SomeRunner is not in the supported-runners registry and its fully-qualified class name is absent from the classpath.

Common situations: Missing the runner-specific dependency (e.g., beam-runners-direct-java not on classpath); typo in the runner class name; using a runner name from a different Beam version.

Related errors


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