ginuerzh/gost · error · net.OpError
write not supported
Error message
write not supported
What it means
The Write method of sshNopConn is a deliberate stub: it always returns a *net.OpError (Op "write", Net "ssh") wrapping "write not supported". This variant of the nop conn exists where the connection is only meant to be read from; writing to it is a usage error.
Source
Thrown at ssh.go:910
Extensions: map[string]string{
"pubkey-fp": ssh.FingerprintSHA256(pubKey),
},
}, nil
}
return nil, fmt.Errorf("unknown public key for %q", c.User())
}
}
type sshNopConn struct {
session *sshSession
}
func (c *sshNopConn) Read(b []byte) (n int, err error) {
return 0, &net.OpError{Op: "read", Net: "ssh", Source: nil, Addr: nil, Err: errors.New("read not supported")}
}
func (c *sshNopConn) Write(b []byte) (n int, err error) {
return 0, &net.OpError{Op: "write", Net: "ssh", Source: nil, Addr: nil, Err: errors.New("write not supported")}
}
func (c *sshNopConn) Close() error {
return nil
}
func (c *sshNopConn) LocalAddr() net.Addr {
return &net.TCPAddr{
IP: net.IPv4zero,
Port: 0,
}
}
func (c *sshNopConn) RemoteAddr() net.Addr {
return &net.TCPAddr{
IP: net.IPv4zero,
Port: 0,
}View on GitHub (pinned to a33fdbf4c9)
Solutions
- Route writes through the real ssh channel-backed connection (sshConn) instead of the nop conn
- Audit the caller: if only reads are expected, remove the write path or assert the conn type before writing
- Handle *net.OpError with Op "write" and Net "ssh" distinctly to surface this misuse early
Example fix
// before conn.Write(req) // conn is sshNopConn -> write not supported // after channel.Write(req) // write via the ssh channel
Defensive patterns
Strategy: type-guard
Validate before calling
func canWrite(c net.Conn) bool {
_, nop := c.(*sshNopConn)
return !nop
} Type guard
func asWriter(c net.Conn) (io.Writer, bool) {
if _, nop := c.(*sshNopConn); nop { return nil, false }
return c, true
} Try / catch
_, err := conn.Write(data)
if err != nil {
var opErr *net.OpError
if errors.As(err, &opErr) && opErr.Net == "ssh" && opErr.Op == "write" {
return fmt.Errorf("ssh conn is read-only: %w", err)
}
return err
} Prevention
- Check conn type before write paths; route writes to the ssh channel instead
- Do not hand sshNopConn to HTTP/TLS transports that will send bytes
- Document the read-only nature of the conn at the handoff point
When it happens
Trigger: Calling Write on a *sshNopConn, e.g. io.Copy(nopConn, src), conn.Write(payload), or an HTTP/TLS layer attempting to send bytes over this conn.
Common situations: Using the nop conn as a generic net.Conn in a transport that sends a request; misconfiguration where the write-side channel was supposed to be the real ssh channel.
Related errors
AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02).
Data as JSON: /api/errors/850a81a934371f65.
Report an issue: GitHub.