ginuerzh/gost · error
read from closed connection
Error message
read from closed connection
What it means
udpConn.ReadFrom returns this error when the connection's `closed` channel has been signaled, meaning ReadFrom was called on an already-closed UDP connection. Any buffered packets in rChan are discarded once closed, so subsequent reads fail with this sentinel.
Source
Thrown at udp.go:249
}
go c.ttlWait()
return c
}
func (c *udpServerConn) Read(b []byte) (n int, err error) {
n, _, err = c.ReadFrom(b)
return
}
func (c *udpServerConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
select {
case bb := <-c.rChan:
n = copy(b, bb)
if cap(bb) == mediumBufferSize {
mPool.Put(bb[:cap(bb)])
}
case <-c.closed:
err = errors.New("read from closed connection")
return
}
select {
case c.nopChan <- n:
default:
}
addr = c.raddr
return
}
func (c *udpServerConn) Write(b []byte) (n int, err error) {
return c.WriteTo(b, c.raddr)
}
func (c *udpServerConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {View on GitHub (pinned to a33fdbf4c9)
Solutions
- Exit the read loop when this error is returned — the connection is closed and will produce no more data.
- Cancel read goroutines (context or done channel) before or atomically with closing the connection.
- Treat this error as io.EOF/io.ErrClosedPipe equivalent and stop reading rather than retrying.
Example fix
// before
for {
n, addr, err := conn.ReadFrom(buf)
if err != nil {
log.Println(err)
continue // spins on closed conn
}
}
// after
for {
n, addr, err := conn.ReadFrom(buf)
if err != nil {
return // conn closed; stop reading
}
}
Defensive patterns
Strategy: type-guard
Validate before calling
select {
case <-c.done:
return // skip reads after shutdown signaled
default:
} Type guard
func isConnClosedReadErr(err error) bool {
return err != nil && strings.Contains(err.Error(), "read from closed connection")
} Try / catch
n, addr, err := conn.ReadFrom(buf)
if err != nil {
if isConnClosedReadErr(err) { return } // expected during shutdown
log.Printf("read: %v", err)
} Prevention
- Cancel all reader goroutines before/when closing the connection.
- Treat this error like io.EOF: stop reading, don't retry.
- Centralize the read loop so close/read teardown is ordered once.
- Use context.Done() alongside read completion to avoid races.
When it happens
Trigger: Calling Read/ReadFrom on a *udpConn after Close() has completed; a read goroutine still blocked on rChan when another goroutine closes the connection.
Common situations: Relay/pump goroutines not cancelled before connection close; closing the conn in a timeout handler while a reader is active; double-close cleanup paths.
Related errors
AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02).
Data as JSON: /api/errors/0ec4126e7f4edecc.
Report an issue: GitHub.