apache/beam · warning

process has already completed, state

Error message

process has already completed, state: %v

What it means

StopService also refuses to kill a process that has already exited: when cmd.ProcessState is non-nil the OS has reaped the child, so Kill is meaningless. The error reports the completed state, meaning StopService was called twice or after natural service termination.

Solutions

  1. Track whether StopService was already called and skip the second call.
  2. Treat this error as benign in cleanup code — log at debug level and continue.
  3. If the service exits unexpectedly, inspect service logs for the real startup failure.
  4. Check ProcessState in your own code before calling StopService if you need certainty.

Example fix

// before
defer runner.StopService()
// after
var stopped bool
defer func() {
    if !stopped {
        stopped = true
        _ = runner.StopService()
    }
}()
Defensive patterns

Strategy: try-catch

Validate before calling

if runnerDone { return nil } // track completion of the service process yourself

Try / catch

if err := runner.StopService(); err != nil {
    if strings.Contains(err.Error(), "already completed") {
        return nil // benign double-stop
    }
    return err
}

Prevention

When it happens

Trigger: Calling StopService() on a runner whose service process already exited (crashed, was killed elsewhere, or StopService was already invoked), or after StartService returned because the command finished.

Common situations: Double cleanup in defer blocks plus explicit Stop; the expansion service crashed on startup and later cleanup tries to kill it; short-lived services that exit on their own.

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/37968883ec75a0e9. Report an issue: GitHub.

Appendix: source

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

		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)