apache/beam · error · RuntimeError

Worker subprocess exited with return code

Error message

Worker subprocess exited with return code %s

What it means

The WorkerHandler used by the embedded local runner launches the SDK harness as a shell subprocess and blocks on p.wait(). If the process exits with a nonzero return code, the runner raises RuntimeError reporting that code, since the worker died abnormally instead of completing its work.

Solutions

  1. Check the logging server output above the error for the harness's actual traceback.
  2. Install missing dependencies in the worker environment (or bundle with --worker_options / requirements).
  3. Fix user code that raises at import/Deserialization time on the worker (use cloudpickle-compatible, importable code).
  4. Investigate return codes: 137/-9 indicates OOM — increase memory or reduce parallelism.
Defensive patterns

Strategy: try-catch

Validate before calling

env_ok = all(dep_importable(d) for d in required_deps)

Try / catch

try:
    handler.run(worker_command)
except RuntimeError as e:
    rc = int(str(e).rsplit(' ', 1)[-1])
    if abs(rc) in (9, 137): investigate_oom()
    else: inspect_harness_logs()

Prevention

When it happens

Trigger: The SDK harness subprocess started by run() crashes: unhandled exception in user code at harness startup, import errors, OOM kill (return code -9/137), or bad worker command line/environment.

Common situations: Missing dependencies in the worker environment; container/OS OOM killer terminating the harness; python version mismatch; failing --worker_command_line overrides; exceptions during pipeline deserialization (pickled DoFn unavailable on worker).

Related errors


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

Appendix: source

Thrown at sdks/python/apache_beam/runners/portability/local_job_service.py:224

        endpoints_pb2.ApiServiceDescriptor(url=self._control_address))
    pipeline_options = json_format.MessageToJson(
        self._provision_info.provision_info.pipeline_options)

    env_dict = dict(
        os.environ,
        CONTROL_API_SERVICE_DESCRIPTOR=control_descriptor,
        LOGGING_API_SERVICE_DESCRIPTOR=logging_descriptor,
        PIPELINE_OPTIONS=pipeline_options)
    # only add worker_id when it is set.
    if self._worker_id:
      env_dict['WORKER_ID'] = self._worker_id

    with worker_handlers.SUBPROCESS_LOCK:
      p = subprocess.Popen(self._worker_command_line, shell=True, env=env_dict)
    try:
      p.wait()
      if p.returncode:
        raise RuntimeError(
            'Worker subprocess exited with return code %s' % p.returncode)
    finally:
      if p.poll() is None:
        p.kill()
      logging_server.stop(0)


class BeamJob(abstract_job_service.AbstractBeamJob):
  """This class handles running and managing a single pipeline.

    The current state of the pipeline is available as self.state.
    """
  def __init__(
      self,
      job_id: str,
      pipeline,
      options,
      provision_info: fn_runner.ExtendedProvisionInfo,

View on GitHub (pinned to 12126d8942)