wavetermdev/waveterm · error

error reading input: %w

Error message

error reading input: %w

What it means

PtyBuffer.run reads from the underlying PTY/pipe reader in a loop and hands bytes to processData. If a read returns an error other than io.EOF, the buffer stores it wrapped as "error reading input: %w" and stops. Anyone reading from the PtyBuffer (MakePtyBuffer consumers) subsequently receives this error, meaning the terminal data stream terminated abnormally rather than cleanly at EOF.

Source

Thrown at pkg/wshutil/wshcmdreader.go:83

	b.CVar.Broadcast()
}

func (b *PtyBuffer) processWaveEscSeq(escSeq []byte) {
	b.MessageCh <- baseds.RpcInputChType{MsgBytes: escSeq}
}

func (b *PtyBuffer) run() {
	defer close(b.MessageCh)
	buf := make([]byte, 4096)
	for {
		n, err := b.InputReader.Read(buf)
		b.processData(buf[:n])
		if err == io.EOF {
			b.setEOF()
			return
		}
		if err != nil {
			b.setErr(fmt.Errorf("error reading input: %w", err))
			return
		}
	}
}

func (b *PtyBuffer) processData(data []byte) {
	outputBuf := make([]byte, 0, len(data))
	for _, ch := range data {
		if b.EscMode == Mode_WaveEsc {
			if ch == ESC {
				// terminates the escape sequence (and the rest was invalid)
				b.EscMode = Mode_Normal
				outputBuf = append(outputBuf, b.EscSeqBuf...)
				outputBuf = append(outputBuf, ch)
				b.EscSeqBuf = nil
			} else if ch == BEL || ch == ST {
				// terminates the escpae sequence (is a valid Wave OSC command)
				b.EscMode = Mode_Normal

View on GitHub (pinned to a4447c1563)

Solutions

  1. Inspect the wrapped inner error (%w) — on Linux an EIO from a PTY read after the child exits usually means the process ended; treat it as end-of-stream if exit status is already captured.
  2. Check the state of the process attached to the PTY (wsh ps / ps aux) and restart it if it died unexpectedly.
  3. Ensure the reader backing the PtyBuffer is valid and not closed by another goroutine; close the buffer itself when done to avoid reading a dead fd.
  4. If this happens reproducibly on session exit, upgrade Wave Terminal — PTY teardown handling (EIO-as-EOF) is a common PTY library fix.

Example fix

// before: reading from a PtyBuffer whose PTY died, surfacing raw error
data, err := ptyBuffer.Read(ctx) // error reading input: read /dev/ptmx: input/output error
// after: tolerate EIO-at-exit as normal termination
data, err := ptyBuffer.Read(ctx)
if err != nil && strings.Contains(err.Error(), "input/output error") && cmdDone {
    err = io.EOF // process already exited; treat as end of stream
}
Defensive patterns

Strategy: try-catch

Try / catch

data, err := ptyBuffer.Read(ctx)
if err != nil {
    var ptyErr error
    if errors.As(err, &ptyErr) && strings.Contains(err.Error(), "error reading input") {
        if isEioAfterExit(err) { // treat EIO after child exit as EOF
            return io.EOF
        }
        return fmt.Errorf("pty stream failed: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: The PTY master/child side is closed abruptly (process killed, file descriptor invalid), an I/O error occurs on the underlying reader (EIO after the child exits on Linux PTYs), or the source file/pipe is closed while MakePtyBuffer is still reading.

Common situations: Shell process crashes or is OOM-killed while output is being streamed; terminal block reading a PTY whose child exited causing EIO instead of EOF; container/SSH sessions dropping mid-stream.

Related errors


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