{"record":{"id":"37968883ec75a0e9","repo":"apache/beam","slug":"process-has-already-completed-state-v","errorCode":null,"errorMessage":"process has already completed, state: %v","messagePattern":"process has already completed, state: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"sdks/go/pkg/beam/core/runtime/xlangx/expansionx/process.go","lineNumber":123,"sourceCode":"\t\treturn err\n\t}\n\n\terr = e.pingEndpoint(connectionTimeout)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// StopService stops the expansion service for a given ExpansionServiceRunner. Returns an error\n// if the command hasn't been run or if the process has already exited.\nfunc (e *ExpansionServiceRunner) StopService() error {\n\texpansionProcess := e.serviceCommand.Process\n\tif expansionProcess == nil {\n\t\treturn fmt.Errorf(\"process does not exist for runner %v\", e)\n\t}\n\tif e.serviceCommand.ProcessState != nil {\n\t\treturn fmt.Errorf(\"process has already completed, state: %v\", e)\n\t}\n\treturn expansionProcess.Kill()\n}\n","sourceCodeStart":105,"sourceCodeEnd":127,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/runtime/xlangx/expansionx/process.go#L105-L127","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Track whether StopService was already called and skip the second call.","Treat this error as benign in cleanup code — log at debug level and continue.","If the service exits unexpectedly, inspect service logs for the real startup failure.","Check ProcessState in your own code before calling StopService if you need certainty."],"exampleFix":"// before\ndefer runner.StopService()\n// after\nvar stopped bool\ndefer func() {\n    if !stopped {\n        stopped = true\n        _ = runner.StopService()\n    }\n}()","handlingStrategy":"try-catch","validationCode":"if runnerDone { return nil } // track completion of the service process yourself","typeGuard":null,"tryCatchPattern":"if err := runner.StopService(); err != nil {\n    if strings.Contains(err.Error(), \"already completed\") {\n        return nil // benign double-stop\n    }\n    return err\n}","preventionTips":["Make Stop idempotent with a boolean guard","Log service crashes instead of failing cleanup","Investigate service logs when the process exits on its own"],"tags":["go","process-lifecycle","expansion-service"],"backgroundTag":"invalid-state-transition","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}