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
- Add the runner's dependency artifact to the classpath (e.g., beam-runners-direct-java, beam-runners-google-cloud-dataflow-java)
- Use a registered short runner name like DirectRunner or DataflowRunner
- 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
- Ensure the runner dependency artifact is on the runtime classpath
- Prefer short registered runner names over FQCNs
- Verify runner availability at startup, not at pipeline submission
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
- Class '%s' does not implement PipelineRunner. Supported pipe
- Runner does not support draining.
- Scheme: [%s] has conflicting filesystems: [%s]
- AutoValue generated class not found: ${generatedClassName}
- Attempted to invoke timer ${timerId} on ${className}, but th
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/1cdafd4f22c13115.
Report an issue: GitHub.