{"record":{"id":"05f9ce8a99008822","repo":"wavetermdev/waveterm","slug":"error-reading-ready-pipe-w","errorCode":null,"errorMessage":"error reading ready pipe: %w","messagePattern":"error reading ready pipe: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wshrpc/wshremote/wshremote_job.go","lineNumber":223,"sourceCode":"\t\t\tlog.Printf(\"RemoteStartJobCommand: error reading stdout: %v\\n\", err)\n\t\t} else {\n\t\t\tlog.Printf(\"RemoteStartJobCommand: stdout EOF\\n\")\n\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\")","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wshrpc/wshremote/wshremote_job.go#L205-L241","documentation":"The goroutine scanning the readiness pipe hit a read error (scanner.Err() != nil) instead of receiving the 'Wave-JobManagerStart' signal. The error is forwarded through startCh and returned to the caller, which kills the child process.","triggerScenarios":"Reading fd 3 (the ready pipe inherited via ExtraFiles) fails mid-stream — e.g. the fd was closed unexpectedly, the pipe buffer state is corrupt, or the child manipulated its inherited fd 3.","commonSituations":"Child process closing or reusing fd 3 incorrectly (version mismatch or a foreign 'wsh' binary); I/O errors on the pipe under extreme system stress.","solutions":["Check the stderr goroutine logs for the jobmanager's own error output","Ensure the installed wsh binary version supports the jobmanager ready-pipe protocol (re-run 'wsh init')","Retry the job start; if persistent, inspect the wsh binary and its fd-3 usage"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"out, err := exec.Command(wshPath, \"--version\").CombinedOutput()\nif err != nil {\n    return fmt.Errorf(\"wsh binary unusable on remote: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"rtn, err := server.RemoteStartJobCommand(ctx, data)\nif err != nil {\n    if strings.Contains(err.Error(), \"error reading ready pipe\") {\n        // transient pipe failure: retry once after checking wsh version\n    }\n    return err\n}","preventionTips":["Keep the remote wsh binary current ('wsh init')","Never let other code touch the child's inherited fd 3","Log stderr lines to diagnose the underlying I/O failure"],"tags":["pipes","process-protocol","read-error","ready-signal"],"backgroundTag":"pipe-read-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}