wavetermdev/waveterm · error

reading from stdin: %w

Error message

reading from stdin: %w

What it means

Wraps any error from io.ReadAll(os.Stdin) when the `-` argument is used in `wsh ai`. Reading stdin failed at the OS level (I/O error, closed/broken pipe, EINTR, etc.). The original error is preserved via %w for errors.Is/As inspection.

Source

Thrown at cmd/wsh/cmd/wshcmd-ai.go:103

	if len(args) > maxFileCount {
		return fmt.Errorf("too many files (maximum %d files allowed)", maxFileCount)
	}

	for _, filePath := range args {
		var data []byte
		var fileName string
		var mimeType string
		var err error

		if filePath == "-" {
			if stdinUsed {
				return fmt.Errorf("stdin (-) can only be used once")
			}
			stdinUsed = true

			data, err = io.ReadAll(os.Stdin)
			if err != nil {
				return fmt.Errorf("reading from stdin: %w", err)
			}
			fileName = "stdin"
			mimeType = "text/plain"
		} else {
			fileInfo, err := os.Stat(filePath)
			if err != nil {
				return fmt.Errorf("accessing file %s: %w", filePath, err)
			}
			absPath, err := filepath.Abs(filePath)
			if err != nil {
				return fmt.Errorf("getting absolute path for %s: %w", filePath, err)
			}

			if fileInfo.IsDir() {
				result, err := fileutil.ReadDir(filePath, 500)
				if err != nil {
					return fmt.Errorf("reading directory %s: %w", filePath, err)
				}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Ensure stdin is actually provided: `cat file | wsh ai -` instead of a bare `wsh ai -` in a non-interactive shell.
  2. Check the upstream producer did not exit early; rerun the pipeline and fix the producing command first (inspect the wrapped error).
  3. If stdin may be closed, pass a file path instead of `-`.
  4. Retry on transient I/O errors (EINTR) — rerun the command.

Example fix

// before (in CI, stdin closed)
$ wsh ai -
// after
$ cat report.txt | wsh ai - --message "summarize"
Defensive patterns

Strategy: try-catch

Validate before calling

if [ -t 0 ] || [ ! -r /dev/stdin ]; then
  echo "wsh ai '-' requires piped stdin, e.g. cat file | wsh ai -" >&2
  exit 1
fi

Try / catch

if err := runAI(); err != nil {
    var perr *os.PathError
    if errors.As(err, &perr) && errors.Is(err, syscall.EPIPE) {
        // upstream writer died; retry the pipeline after fixing the producer
    } else {
        return fmt.Errorf("stdin read failed: %w", err)
    }
}

Prevention

When it happens

Trigger: `wsh ai -` where stdin is closed or not connected (no pipe/redirection in a non-tty context), the upstream writer process died mid-stream (broken pipe), or an OS I/O error (disk/device failure, interrupted read) occurs during the read.

Common situations: CI jobs invoking `wsh ai -` without piping anything and stdin closed; `someproc | wsh ai -` where someproc crashed; running under a supervisor that detached stdin.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/16e6ebe75e954da9. Report an issue: GitHub.