apache/beam · error · Error

Unknown runner

Error message

Unknown runner: ${options.runner}

What it means

createRunner maps the options.runner name to a constructor via a fixed if/else chain (direct, universal, flink, dataflow). Any other runner string falls to the else branch and throws 'Unknown runner: <name>'. It is a configuration validation error for an unrecognized runner identifier.

Solutions

  1. Set options.runner to one of the supported values: 'direct', 'universal', 'flink', or 'dataflow'.
  2. Check for case/typo errors in the runner string.
  3. Register your own runner by calling its constructor directly instead of going through createRunner.

Example fix

// before
const runner = await createRunner({ runner: "spark" });
// after
const runner = await createRunner({ runner: "flink" });
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED = ["direct", "universal", "flink", "dataflow"];
if (!SUPPORTED.includes(options.runner)) throw new Error(`runner must be one of ${SUPPORTED.join(", ")}`);

Type guard

function isKnownRunner(r: string): r is "direct" | "universal" | "flink" | "dataflow" {
  return ["direct", "universal", "flink", "dataflow"].includes(r);
}

Try / catch

try {
  const runner = await createRunner(options);
} catch (e) {
  if (e.message.startsWith("Unknown runner:")) {
    console.error(`Invalid runner '${options.runner}'. Use direct|universal|flink|dataflow.`);
  } else throw e;
}

Prevention

When it happens

Trigger: Passing options.runner set to a misspelled or unsupported value (e.g. 'spark', 'Direct', 'FlinkRunner') to createRunner or main().

Common situations: Typos in pipeline options files, copying runner names from other Beam SDKs (Python's 'SparkRunner'), or using a runner that the TypeScript SDK simply does not ship.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at sdks/typescript/src/apache_beam/runners/runner.ts:79

 * a direct runner.  If no runner option is specified, the "default" runner
 * is used, which runs what pipelines it can on the direct runner, and
 * otherwise falls back to the universal runner (e.g. if cross-language
 * transforms, non-trivial windowing, etc. are used).
 */
export function createRunner(options: any = {}): Runner {
  let runnerConstructor: (any) => Runner;
  if (options.runner === undefined || options.runner === "default") {
    runnerConstructor = defaultRunner;
  } else if (options.runner === "direct") {
    runnerConstructor = require("./direct_runner").directRunner;
  } else if (options.runner === "universal") {
    runnerConstructor = require("./universal").universalRunner;
  } else if (options.runner === "flink") {
    runnerConstructor = require("./flink").flinkRunner;
  } else if (options.runner === "dataflow") {
    runnerConstructor = require("./dataflow").dataflowRunner;
  } else {
    throw new Error("Unknown runner: " + options.runner);
  }
  return runnerConstructor(options);
}

/**
 * A Runner is the object that takes a pipeline definition and actually
 * executes, e.g. locally or on a distributed system, by invoking its
 * `run` or `runAsync` method.
 *
 * Runners are generally created using the `createRunner` method in this
 * same module.
 */
export abstract class Runner {
  /**
   * Runs the transform.
   *
   * Resolves to an instance of PipelineResult when the pipeline completes.
   * Use runAsync() to execute the pipeline in the background.

View on GitHub (pinned to 12126d8942)