ginuerzh/gost · error · net.OpError

read not supported

Error message

read not supported

What it means

nopConn is a do-nothing net.Conn (a sink/discarded connection); its Read always fails with a *net.OpError whose Err is 'read not supported'. The library throws this because a nop connection has no peer and no data stream — reading from it is meaningless. It exists so code that requires a net.Conn can be handed a harmless placeholder.

Source

Thrown at gost.go:159

	w io.Writer
}

func (rw *readWriter) Read(p []byte) (n int, err error) {
	return rw.r.Read(p)
}

func (rw *readWriter) Write(p []byte) (n int, err error) {
	return rw.w.Write(p)
}

var nopClientConn = &nopConn{}

// a nop connection implements net.Conn,
// it does nothing.
type nopConn struct{}

func (c *nopConn) Read(b []byte) (n int, err error) {
	return 0, &net.OpError{Op: "read", Net: "nop", Source: nil, Addr: nil, Err: errors.New("read not supported")}
}

func (c *nopConn) Write(b []byte) (n int, err error) {
	return 0, &net.OpError{Op: "write", Net: "nop", Source: nil, Addr: nil, Err: errors.New("write not supported")}
}

func (c *nopConn) Close() error {
	return nil
}

func (c *nopConn) LocalAddr() net.Addr {
	return nil
}

func (c *nopConn) RemoteAddr() net.Addr {
	return nil
}

View on GitHub (pinned to a33fdbf4c9)

Solutions

  1. Don't read from nopConn — it is write/discarded-traffic only; restructure so no Read is attempted
  2. If you need a readable placeholder, substitute a net.Pipe() connection or an empty reader wrapped appropriately
  3. Check the *net.OpError's Err message ('read not supported') and skip reads for nop connections
  4. If you own the code, implement Read to return io.EOF instead of an error if silent termination is desired

Example fix

// before
io.Copy(dst, nop) // always errors: read not supported
// after
if _, ok := conn.(*gost.NopConn); ok {
  // nothing to relay from a nop connection
  return nil
}
io.Copy(dst, conn)
Defensive patterns

Strategy: type-guard

Validate before calling

if _, ok := conn.(*gostNopConn); ok {
    // nop connection is not readable; skip the read path
    return nil
}

Type guard

func isNopConn(c net.Conn) bool {
    return fmt.Sprintf("%T", c) == "*gost.nopConn"
}

Try / catch

n, err := conn.Read(buf)
if err != nil {
    var oe *net.OpError
    if errors.As(err, &oe) && oe.Err.Error() == "read not supported" {
        return nil // expected for nop connections
    }
    return err
}

Prevention

When it happens

Trigger: Any call to Read(b []byte) on a value of type *nopConn, e.g. when code copies/relays from a connection that was substituted with a nopConn (bypass node, discarded traffic, testing placeholder).

Common situations: io.Copy from a nopConn in a relay pair; generic code that assumes every net.Conn is readable; tests that accidentally wire the nop connection into a data path.

Related errors


AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02). Data as JSON: /api/errors/52089db9cde151b0. Report an issue: GitHub.