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_NormalView on GitHub (pinned to a4447c1563)
Solutions
- 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.
- Check the state of the process attached to the PTY (wsh ps / ps aux) and restart it if it died unexpectedly.
- 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.
- 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
- Always close the PtyBuffer when the underlying process exits to stop reads on a dead fd.
- Treat PTY EIO after child exit as end-of-stream, not a fatal error.
- Monitor the attached process health; restart the shell if it was killed.
- Keep Wave Terminal updated — PTY teardown behavior differs across platforms and is patched regularly.
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
- error appending to blockfile: %w
- failed to send input to job: %w
- invalid term size: %v
- no active pty
- error setting terminal size: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/21b20ea9db93cce9.
Report an issue: GitHub.