yudai/gotty · error
unexpected zero length read from master
Error message
unexpected zero length read from master
What it means
WebTTY's handleMasterReadEvent() guards against empty reads from the PTY master side. A zero-length slice carries no message type byte, so it cannot be dispatched; the library treats it as an unexpected condition rather than silently ignoring it.
Source
Thrown at webtty/webtty.go:160
return nil
}
func (wt *WebTTY) masterWrite(data []byte) error {
wt.writeMutex.Lock()
defer wt.writeMutex.Unlock()
_, err := wt.masterConn.Write(data)
if err != nil {
return errors.Wrapf(err, "failed to write to master")
}
return nil
}
func (wt *WebTTY) handleMasterReadEvent(data []byte) error {
if len(data) == 0 {
return errors.New("unexpected zero length read from master")
}
switch data[0] {
case Input:
if !wt.permitWrite {
return nil
}
if len(data) <= 1 {
return nil
}
_, err := wt.slave.Write(data[1:])
if err != nil {
return errors.Wrapf(err, "failed to write received data to slave")
}
case Ping:View on GitHub (pinned to a080c85cbc)
Solutions
- Check the wrapped PTY/slave reader: its Read must return io.EOF at end-of-stream, never (0, nil)
- Skip zero-length reads in custom slave implementations before invoking WebTTY
- If it happens at shutdown, treat it as benign teardown noise
Example fix
// before (custom slave Read)
return 0, nil
// after
if n == 0 && err == nil {
return 0, io.EOF
}
return n, err Defensive patterns
Strategy: type-guard
Validate before calling
if len(data) > 0 {
if err := wt.handleMasterReadEvent(data); err != nil { ... }
} Type guard
func readableData(data []byte) bool { return len(data) > 0 } Try / catch
if err := runWebTTY(ctx); err != nil {
if err.Error() == "unexpected zero length read from master" {
// treat as EOF/teardown or wrap slave reads to skip empties
}
} Prevention
- Implement io.Reader for PTY slaves correctly: return io.EOF, never (0, nil)
- Filter empty reads before dispatching into WebTTY
When it happens
Trigger: The master (PTY) read loop delivering a 0-byte data slice into handleMasterReadEvent — typically when a read returns success with no bytes or a caller passes an empty buffer.
Common situations: Race during PTY teardown where a read returns (nil/empty, nil); wrapping a slave whose Read returns 0, nil incorrectly (io.Reader implementations should return io.EOF instead of 0, nil).
AI-assisted analysis of yudai/gotty@a080c85cbc (2026-09-02).
Data as JSON: /api/errors/70ab3c725e0d05f1.
Report an issue: GitHub.