{"record":{"id":"850a81a934371f65","repo":"ginuerzh/gost","slug":"write-not-supported-850a81","errorCode":null,"errorMessage":"write not supported","messagePattern":"write not supported","errorType":"exception","errorClass":"net.OpError","httpStatus":null,"severity":"error","filePath":"ssh.go","lineNumber":910,"sourceCode":"\t\t\t\tExtensions: map[string]string{\n\t\t\t\t\t\"pubkey-fp\": ssh.FingerprintSHA256(pubKey),\n\t\t\t\t},\n\t\t\t}, nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"unknown public key for %q\", c.User())\n\t}\n}\n\ntype sshNopConn struct {\n\tsession *sshSession\n}\n\nfunc (c *sshNopConn) Read(b []byte) (n int, err error) {\n\treturn 0, &net.OpError{Op: \"read\", Net: \"ssh\", Source: nil, Addr: nil, Err: errors.New(\"read not supported\")}\n}\n\nfunc (c *sshNopConn) Write(b []byte) (n int, err error) {\n\treturn 0, &net.OpError{Op: \"write\", Net: \"ssh\", Source: nil, Addr: nil, Err: errors.New(\"write not supported\")}\n}\n\nfunc (c *sshNopConn) Close() error {\n\treturn nil\n}\n\nfunc (c *sshNopConn) LocalAddr() net.Addr {\n\treturn &net.TCPAddr{\n\t\tIP:   net.IPv4zero,\n\t\tPort: 0,\n\t}\n}\n\nfunc (c *sshNopConn) RemoteAddr() net.Addr {\n\treturn &net.TCPAddr{\n\t\tIP:   net.IPv4zero,\n\t\tPort: 0,\n\t}","sourceCodeStart":892,"sourceCodeEnd":928,"githubUrl":"https://github.com/ginuerzh/gost/blob/a33fdbf4c98034f4bfeeaea9868909822b9c526d/ssh.go#L892-L928","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nconn.Write(req) // conn is sshNopConn -> write not supported\n// after\nchannel.Write(req) // write via the ssh channel","handlingStrategy":"type-guard","validationCode":"func canWrite(c net.Conn) bool {\n    _, nop := c.(*sshNopConn)\n    return !nop\n}","typeGuard":"func asWriter(c net.Conn) (io.Writer, bool) {\n    if _, nop := c.(*sshNopConn); nop { return nil, false }\n    return c, true\n}","tryCatchPattern":"_, err := conn.Write(data)\nif err != nil {\n    var opErr *net.OpError\n    if errors.As(err, &opErr) && opErr.Net == \"ssh\" && opErr.Op == \"write\" {\n        return fmt.Errorf(\"ssh conn is read-only: %w\", err)\n    }\n    return err\n}","preventionTips":["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"],"tags":["ssh","net-op-error","unsupported-operation","write"],"backgroundTag":"write-not-supported","analyzedSha":"a33fdbf4c98034f4bfeeaea9868909822b9c526d","analyzedAt":"2026-09-02T22:15:54.506Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}