{"record":{"id":"4d42bdf13af67485","repo":"wavetermdev/waveterm","slug":"job-manager-exited-without-start-signal","errorCode":null,"errorMessage":"job manager exited without start signal","messagePattern":"job manager exited without start signal","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wshrpc/wshremote/wshremote_job.go","lineNumber":226,"sourceCode":"\t\t}\n\t}()\n\n\tstartCh := make(chan error, 1)\n\tgo func() {\n\t\tscanner := bufio.NewScanner(readyPipeRead)\n\t\tfor scanner.Scan() {\n\t\t\tline := scanner.Text()\n\t\t\tlog.Printf(\"RemoteStartJobCommand: ready pipe line: %s\\n\", line)\n\t\t\tif strings.Contains(line, \"Wave-JobManagerStart\") {\n\t\t\t\tstartCh <- nil\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tif err := scanner.Err(); err != nil {\n\t\t\tstartCh <- fmt.Errorf(\"error reading ready pipe: %w\", err)\n\t\t} else {\n\t\t\tlog.Printf(\"RemoteStartJobCommand: ready pipe EOF\\n\")\n\t\t\tstartCh <- fmt.Errorf(\"job manager exited without start signal\")\n\t\t}\n\t}()\n\n\ttimeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second)\n\tdefer cancel()\n\n\tlog.Printf(\"RemoteStartJobCommand: waiting for start signal\\n\")\n\tselect {\n\tcase err := <-startCh:\n\t\tif err != nil {\n\t\t\tcmd.Process.Kill()\n\t\t\tlog.Printf(\"RemoteStartJobCommand: error from start signal: %v\\n\", err)\n\t\t\treturn nil, err\n\t\t}\n\t\tlog.Printf(\"RemoteStartJobCommand: received start signal\\n\")\n\tcase <-timeoutCtx.Done():\n\t\tcmd.Process.Kill()\n\t\tlog.Printf(\"RemoteStartJobCommand: timeout waiting for start signal\\n\")","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wshrpc/wshremote/wshremote_job.go#L208-L244","documentation":"The readiness pipe reached EOF without ever containing 'Wave-JobManagerStart', meaning the jobmanager child process exited (closing its write end of fd 3) before signaling readiness. The child is killed and this error returned.","triggerScenarios":"The spawned 'wsh jobmanager' process terminates before sending its start signal — immediate crash, unknown flags, failed auth setup, or binary version mismatch.","commonSituations":"Outdated or mismatched wsh binary on the remote host; jobmanager panicking on startup; environment/config problems killing the child early.","solutions":["Inspect the stderr goroutine logs for the child's exit message","Update the remote wsh binary with 'wsh init' so the jobmanager protocol matches the server","Run the jobmanager command manually to reproduce its startup failure"],"exampleFix":"// before (remote binary too old, dies before signaling)\n$ ssh remote 'wsh jobmanager --jobid x --clientid y'\nError: unknown command \"jobmanager\"\n// after\n$ wsh init   # installs a current wsh binary that supports jobmanager","handlingStrategy":"retry","validationCode":"out, err := exec.Command(wshPath, \"jobmanager\", \"--help\").CombinedOutput()\nif err != nil {\n    return fmt.Errorf(\"remote wsh lacks jobmanager support: %v: %s\", err, out)\n}","typeGuard":null,"tryCatchPattern":"rtn, err := server.RemoteStartJobCommand(ctx, data)\nif err != nil {\n    if strings.Contains(err.Error(), \"exited without start signal\") {\n        // child died early: read captured stderr, fix binary/version, retry\n    }\n    return err\n}","preventionTips":["Update the remote wsh binary after every server upgrade","Always inspect the stderr goroutine logs when this error appears","Smoke-test 'wsh jobmanager' on the remote before production use"],"tags":["process","ready-signal","child-process-exit","protocol"],"backgroundTag":"child-process-exited-early","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}