{"record":{"id":"c10cacd4824df835","repo":"wavetermdev/waveterm","slug":"cannot-write-job-auth-token-w","errorCode":null,"errorMessage":"cannot write job auth token: %w","messagePattern":"cannot write job auth token: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wshrpc/wshremote/wshremote_job.go","lineNumber":180,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"cannot create stdout pipe: %w\", err)\n\t}\n\tstderr, err := cmd.StderrPipe()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"cannot create stderr pipe: %w\", err)\n\t}\n\tlog.Printf(\"RemoteStartJobCommand: created pipes\\n\")\n\n\tif err := cmd.Start(); err != nil {\n\t\treturn nil, fmt.Errorf(\"cannot start job manager: %w\", err)\n\t}\n\treadyPipeWrite.Close()\n\tlog.Printf(\"RemoteStartJobCommand: job manager process started\\n\")\n\n\tjobAuthTokenLine := fmt.Sprintf(\"Wave-JobAccessToken:%s\\n\", data.JobAuthToken)\n\tif _, err := stdin.Write([]byte(jobAuthTokenLine)); err != nil {\n\t\tcmd.Process.Kill()\n\t\treturn nil, fmt.Errorf(\"cannot write job auth token: %w\", err)\n\t}\n\tstdin.Close()\n\tlog.Printf(\"RemoteStartJobCommand: wrote auth token to stdin\\n\")\n\n\tgo func() {\n\t\tscanner := bufio.NewScanner(stderr)\n\t\tfor scanner.Scan() {\n\t\t\tline := scanner.Text()\n\t\t\tlog.Printf(\"RemoteStartJobCommand: stderr: %s\\n\", line)\n\t\t}\n\t\tif err := scanner.Err(); err != nil {\n\t\t\tlog.Printf(\"RemoteStartJobCommand: error reading stderr: %v\\n\", err)\n\t\t} else {\n\t\t\tlog.Printf(\"RemoteStartJobCommand: stderr EOF\\n\")\n\t\t}\n\t}()\n\n\tgo func() {","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wshrpc/wshremote/wshremote_job.go#L162-L198","documentation":"After the jobmanager process starts, RemoteStartJobCommand writes the 'Wave-JobAccessToken:<token>' line to its stdin pipe. A failed write means the pipe is broken — the child has already exited or closed stdin — and the process is killed before returning the wrapped error.","triggerScenarios":"The wsh jobmanager child crashes/exits immediately after Start() (bad flags, missing config, panic), causing the stdin pipe to break when the auth token is written.","commonSituations":"Incompatible wsh binary version on the remote that rejects the jobmanager subcommand; child dying from a missing dependency or configuration; EPIPE on the stdin pipe.","solutions":["Check the captured stderr goroutine logs for the child's actual exit reason","Verify the remote wsh binary version matches the server (re-run 'wsh init' to update)","Run the resolved wsh binary manually with 'jobmanager --jobid ... --clientid ...' to see its immediate error"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// preflight: ensure the jobmanager subcommand exists\nout, err := exec.Command(wshPath, \"jobmanager\", \"--help\").CombinedOutput()\nif err != nil {\n    return fmt.Errorf(\"jobmanager subcommand unavailable: %v: %s\", err, out)\n}","typeGuard":null,"tryCatchPattern":"rtn, err := server.RemoteStartJobCommand(ctx, data)\nif err != nil {\n    if strings.Contains(err.Error(), \"cannot write job auth token\") {\n        // child died before reading stdin; check stderr logs and wsh version\n    }\n    return err\n}","preventionTips":["Keep remote wsh binary version in sync with the server","Correlate this error with the stderr goroutine logs for the child's exit reason","Test jobmanager startup manually after upgrades"],"tags":["process","pipe","broken-pipe","auth-token"],"backgroundTag":"broken-pipe","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}