wavetermdev/waveterm · error
failed to read JWT token from stdin: %w
Error message
failed to read JWT token from stdin: %w
What it means
When wsh connserver is not given a JWT on the command line, askForJwtToken reads one line from stdin with fmt.Fscanln. If stdin is closed, empty, or unreadable, it wraps the failure in this error and server startup aborts.
Source
Thrown at cmd/wsh/cmd/wshcmd-connserver.go:434
select {} // run forever
}
func askForJwtToken() (string, error) {
// if it already exists in the environment, great, use it
jwtToken := os.Getenv(wavebase.WaveJwtTokenVarName)
if jwtToken != "" {
fmt.Printf("HAVE-JWT\n")
return jwtToken, nil
}
// otherwise, ask for it
fmt.Printf("%s\n", wavebase.NeedJwtConst)
// read a single line from stdin
var line string
_, err := fmt.Fscanln(os.Stdin, &line)
if err != nil {
return "", fmt.Errorf("failed to read JWT token from stdin: %w", err)
}
return strings.TrimSpace(line), nil
}
func serverRun(cmd *cobra.Command, args []string) error {
connServerInitialEnv = envutil.PruneInitialEnv(envutil.SliceToMap(os.Environ()))
var logFile *os.File
if connServerDev {
var err error
logFilePath := fmt.Sprintf("/tmp/waveterm-connserver-%d.log", os.Getuid())
logFile, err = os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to open log file: %v\n", err)
log.SetFlags(log.LstdFlags | log.Lmicroseconds)
log.SetPrefix(fmt.Sprintf("[PID:%d] ", os.Getpid()))
} else {
defer logFile.Close()View on GitHub (pinned to a4447c1563)
Solutions
- Pass the token explicitly via the --jwt flag so stdin is not needed
- Pipe the token in: echo "<jwt>" | wsh connserver ...
- Ensure the launching process provides a working stdin pipe
- Check that the parent process (e.g. Wave client) actually writes the token before closing the pipe
Example fix
// before wsh connserver --conn myserver < /dev/null // after wsh connserver --conn myserver --jwt "$WAVETERM_JWT" // or: echo "$WAVETERM_JWT" | wsh connserver --conn myserver
Defensive patterns
Strategy: fallback
Validate before calling
// before spawning, ensure stdin is a readable pipe/file: fi, _ := os.Stdin.Stat() stdinUsable := fi != nil && (fi.Mode()&os.ModeCharDevice) == 0 || fi != nil
Try / catch
line, err := readJwtFromStdin()
if err != nil {
return fmt.Errorf("no JWT on stdin: %w (pass --jwt or pipe the token)", err)
} Prevention
- Prefer the --jwt flag over interactive stdin in scripts/CI
- Pipe the token explicitly: echo "$JWT" | wsh connserver ...
- Ensure service units and daemons provide stdin or avoid stdin-based prompts entirely
- Detect EOF early and fail fast with an actionable message
When it happens
Trigger: wsh connserver runs without --jwt and stdin is at EOF (e.g. spawned with no stdin, </dev/null, or from a daemon/service with no attached stdin), or Fscanln fails on an empty line.
Common situations: Running the command in a CI job or systemd unit where stdin is /dev/null; piping nothing into the command; launching it from a GUI/parent process that does not forward stdin; pressing Ctrl-D immediately at the prompt.
Related errors
- reading from stdin: %w
- reading stdin: %w
- stdin (-) can only be used once
- reading input: %w
- error writing to file %s: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/3a6fd0bbec809609.
Report an issue: GitHub.