apache/beam · warning

process does not exist for runner

Error message

process does not exist for runner %v

What it means

StopService kills the runner's expansion service process. If the underlying exec.Cmd was never started, cmd.Process is nil, and StopService returns "process does not exist for runner %v" instead of attempting a nil-pointer kill. It reflects calling Stop on a runner whose service was never launched.

Solutions

  1. Only call StopService after a successful StartService; guard cleanup with a started flag.
  2. Check the error from StartService before deferring StopService.
  3. If using defer, make the deferred call tolerant of this error (log and continue).

Example fix

// before
runner.StartService()
defer runner.StopService()
// after
if err := runner.StartService(); err != nil {
    return err
}
defer func() {
    if err := runner.StopService(); err != nil {
        log.Printf("stop expansion service: %v", err)
    }
}()
Defensive patterns

Strategy: try-catch

Validate before calling

if !serviceStarted {
    return errors.New("expansion service was never started; skip StopService")
}

Try / catch

if err := runner.StopService(); err != nil {
    log.Printf("stop expansion service (may be benign): %v", err)
}

Prevention

When it happens

Trigger: Calling runner.StopService() after constructing the runner with NewExpansionServiceRunner/NewPyExpansionServiceRunner but never calling StartService(), or after the command failed to spawn.

Common situations: Cleanup paths (deferred StopService) that run when StartService already failed; tests exercising Stop before Start; early-return error paths skipping Start.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at sdks/go/pkg/beam/core/runtime/xlangx/expansionx/process.go:120

func (e *ExpansionServiceRunner) StartService() error {
	err := e.serviceCommand.Start()
	if err != nil {
		return err
	}

	err = e.pingEndpoint(connectionTimeout)
	if err != nil {
		return err
	}
	return nil
}

// StopService stops the expansion service for a given ExpansionServiceRunner. Returns an error
// if the command hasn't been run or if the process has already exited.
func (e *ExpansionServiceRunner) StopService() error {
	expansionProcess := e.serviceCommand.Process
	if expansionProcess == nil {
		return fmt.Errorf("process does not exist for runner %v", e)
	}
	if e.serviceCommand.ProcessState != nil {
		return fmt.Errorf("process has already completed, state: %v", e)
	}
	return expansionProcess.Kill()
}

View on GitHub (pinned to 12126d8942)