wavetermdev/waveterm · error
cannot write job auth token: %w
Error message
cannot write job auth token: %w
What it means
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.
Source
Thrown at pkg/wshrpc/wshremote/wshremote_job.go:180
if err != nil {
return nil, fmt.Errorf("cannot create stdout pipe: %w", err)
}
stderr, err := cmd.StderrPipe()
if err != nil {
return nil, fmt.Errorf("cannot create stderr pipe: %w", err)
}
log.Printf("RemoteStartJobCommand: created pipes\n")
if err := cmd.Start(); err != nil {
return nil, fmt.Errorf("cannot start job manager: %w", err)
}
readyPipeWrite.Close()
log.Printf("RemoteStartJobCommand: job manager process started\n")
jobAuthTokenLine := fmt.Sprintf("Wave-JobAccessToken:%s\n", data.JobAuthToken)
if _, err := stdin.Write([]byte(jobAuthTokenLine)); err != nil {
cmd.Process.Kill()
return nil, fmt.Errorf("cannot write job auth token: %w", err)
}
stdin.Close()
log.Printf("RemoteStartJobCommand: wrote auth token to stdin\n")
go func() {
scanner := bufio.NewScanner(stderr)
for scanner.Scan() {
line := scanner.Text()
log.Printf("RemoteStartJobCommand: stderr: %s\n", line)
}
if err := scanner.Err(); err != nil {
log.Printf("RemoteStartJobCommand: error reading stderr: %v\n", err)
} else {
log.Printf("RemoteStartJobCommand: stderr EOF\n")
}
}()
go func() {View on GitHub (pinned to a4447c1563)
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
Defensive patterns
Strategy: try-catch
Validate before calling
// preflight: ensure the jobmanager subcommand exists
out, err := exec.Command(wshPath, "jobmanager", "--help").CombinedOutput()
if err != nil {
return fmt.Errorf("jobmanager subcommand unavailable: %v: %s", err, out)
} Try / catch
rtn, err := server.RemoteStartJobCommand(ctx, data)
if err != nil {
if strings.Contains(err.Error(), "cannot write job auth token") {
// child died before reading stdin; check stderr logs and wsh version
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- failed to create stdout pipe: %w
- failed to create stderr pipe: %w
- failed to get stdout pipe: %w
- failed to get stderr pipe: %w
- procinfo: process not found
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/c10cacd4824df835.
Report an issue: GitHub.