The connection reset by peer
is a TCP/IP error that occurs when the other end (peer) has unexpectedly closed the connection. It happens when you send a packet from your end, but the other end crashes and forcibly closes the connection with the RST
packet instead of the TCP FIN
, which is used to close a connection under normal circumstances. In Go, you can detect the connection reset by peer
by checking if the error returned by the peer is equal to syscall.ECONNRESET
.
Reproduce the connection reset by peer
error
We can reproduce the error by creating a server and client that do the following:
- the server reads a single byte and then closes the connection
- the client sends more than one byte
If the server closes the connection with the remaining bytes in the socket’s receive buffer, then an RST
packet is sent to the client. When the client tries to read from such a closed connection, it will get the connection reset by peer
error.
See the following example, which simulates this behavior.
package main
import (
"errors"
"log"
"net"
"os"
"syscall"
"time"
)
func server() {
listener, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatal(err)
}
defer listener.Close()
conn, err := listener.Accept()
if err != nil {
log.Fatal("server", err)
os.Exit(1)
}
data := make([]byte, 1)
if _, err := conn.Read(data); err != nil {
log.Fatal("server", err)
}
conn.Close()
}
func client() {
conn, err := net.Dial("tcp", "localhost:8080")
if err != nil {
log.Fatal("client", err)
}
if _, err := conn.Write([]byte("ab")); err != nil {
log.Printf("client: %v", err)
}
time.Sleep(1 * time.Second) // wait for close on the server side
data := make([]byte, 1)
if _, err := conn.Read(data); err != nil {
log.Printf("client: %v", err)
if errors.Is(err, syscall.ECONNRESET) {
log.Print("This is connection reset by peer error")
}
}
}
func main() {
go server()
time.Sleep(3 * time.Second) // wait for server to run
client()
}
Output:
2021/10/20 19:01:58 client: read tcp [::1]:59897->[::1]:8080: read: connection reset by peer
2021/10/20 19:01:58 This is connection reset by peer error
Handle the connection reset by peer
error
Typically, you can see the connection reset by peer
error in response to a request being sent from the client to the server. It means that something bad has happened to the server: it has rebooted, the program has crashed, or other problems have occurred that cause the connection to be forcibly closed. Since TCP connections can be broken, there is no need to handle the connection reset by peer
in any special way on the client side. You can log the error, ignore it or retry the connection when it occurs. In the example above, we detect the error using the errors.Is()
function by checking if the returned error is an instance of syscall.ECONNRESET
.
Difference between connection reset by peer
and broken pipe
Both connection reset by peer
and broken pipe
errors occur when a peer (the other end) unexpectedly closes the underlying connection. However, there is a subtle difference between them. Usually, you get the connection reset by peer
when you read from the connection after the server sends the RST
packet, and when you write to the connection after the RST
instead, you get the broken pipe
error.
Check how to handle the
broken pipe
error in Go post, where will find another example of generating anRST
packet and thebroken pipe
error.
Replace the client()
function in the example above with the following code to reproduce the broken pipe
error.
func client() {
conn, err := net.Dial("tcp", "localhost:8080")
if err != nil {
log.Fatal("client", err)
}
if _, err := conn.Write([]byte("ab")); err != nil {
log.Printf("client: %v", err)
}
time.Sleep(1 * time.Second) // wait for close on the server side
if _, err := conn.Write([]byte("b")); err != nil {
log.Printf("client: %v", err)
}
}
With the new client, you will see the output:
2021/10/20 19:55:40 client: write tcp [::1]:60399->[::1]:8080: write: broken pipe
Note that these simple examples do not cover all cases where connection reset by peer
and broken pipe
may occur. There are much more situations where you can see these errors, and what error you see in what situation requires a deep understanding of the TCP design.